OSC++.035 — std::bind_back: binding trailing arguments in C++23. The C++ standard library provides multiple ways to turn an existing function into a more specialized callable. C++23 introduced std::bind_back, which stores one or more last arguments of an existing callable and leaves the earlier arguments to be supplied later. It complements the earlier std::bind_front lesson and builds on std::invoke and callable objects. This entry explains partial application, argument order, copies and references, compiler availability, and practical examples.
Definition and standard-library availability
std::bind_back is declared in <functional> beginning with C++23. It returns a new function object whose call forwards the newly supplied arguments to the original callable before the stored trailing arguments. In simplified mathematical form, std::bind_back(f, y)(x) behaves like f(x, y). The C++ reference specification states the exact behavior in terms of std::invoke, including forwarding and exception behavior. This is a library feature, not a new C++ language keyword.
The companion function std::bind_front has existed since C++20 and stores leading arguments. The distinction is especially important for subtraction, comparison, filtering, log formatting and callbacks because argument order can change meaning. C++23 library support varies by compiler and standard library release; enabling -std=c++23 or an equivalent language setting is necessary but not, by itself, proof that every C++23 facility is implemented.
A first example — subtracting from opposite ends
Suppose a function accepts two integers in order: subtract(lhs, rhs). Binding the second parameter to five creates a function that subtracts five from whatever comes next. Binding the first parameter to five instead creates a function that subtracts the later input from five. The difference becomes visible when the input is 12.
#include <functional>
#include <iostream>
#include <version>
int subtract(int lhs, int rhs) {
return lhs - rhs;
}
int main() {
#if defined(__cpp_lib_bind_back) && __cpp_lib_bind_back >= 202202L
auto minus_five = std::bind_back(subtract, 5);
auto from_five = std::bind_front(subtract, 5);
std::cout << minus_five(12) << "\n"; // 7
std::cout << from_five(12) << "\n"; // -7
#else
std::cout << "std::bind_back unavailable\n";
#endif
}
The C++23 branch prints 7 followed by -7. This complete example was compiled using GCC 14 with C++23 enabled, and its output matched those results. The check using __cpp_lib_bind_back makes the example report when the standard-library implementation lacks the feature rather than blindly assuming it is available.
Video lesson — C++23’s bind_back
Jason Turner’s C++ Weekly episode concentrates specifically on std::bind_back, including how binding trailing parameters can simplify call sites and how its implementation relates to modern lambdas. It provides a useful companion demonstration to the examples in this article. The video’s original C++ Weekly episode page directly identifies the YouTube source.
Partial application without positional placeholders
Historically, std::bind allowed placeholders such as std::placeholders::_1, and complex expressions could reorder argument positions. std::bind_front and std::bind_back instead intentionally support only binding at one end. This makes the code easier to audit and typically less surprising. The simpler binders do not automatically rearrange or interpret nested bind expressions; the standard-library reference documents the behavioral differences.
For many short callbacks, an ordinary lambda can be clearer still. These tools are complementary: use a named binder when attaching a stable configuration value is the central idea; use a lambda when the logic includes a condition, transformation, or a more involved expression. Avoid treating the introduction of a new standard-library utility as a requirement to replace all readable lambdas.
Practical example — fixed error-message prefix
A diagnostic parser may need to detect whether messages begin with a particular prefix. A reusable predicate can be constructed by binding the final prefix argument of a function-like object while leaving the message to be supplied later.
#include <functional>
#include <iostream>
#include <string>
#include <version>
int main() {
#if defined(__cpp_lib_bind_back) && __cpp_lib_bind_back >= 202202L
auto starts_with_error = std::bind_back(
[](const std::string& message, const std::string& prefix) {
return message.rfind(prefix, 0) == 0;
},
std::string("error:")
);
std::cout << std::boolalpha
<< starts_with_error(std::string("error: timeout"))
<< "\n"; // true
#else
std::cout << "Use a lambda fallback\n";
#endif
}
The C++23 implementation prints true for the illustrative message. The bound prefix is stored inside the returned callable rather than re-created by every invocation. A straightforward lambda with the prefix captured by value could express the same behavior. This pattern appears in parser configuration, application logging, optional-value handling, and algorithms that expect a one-argument predicate.
Video comparison — std::bind_front in C++20
The preceding C++20 feature helps explain the other half of partial application. Jason Turner’s earlier demonstration shows why fixing the front of an argument list is useful; compare it with the first video to see that bind_back does the same kind of specialization at the opposite end.
How bound values are stored
A binder stores its target callable and its bound arguments using decayed stored types. That normally means copying an lvalue or moving an rvalue into the wrapper at construction. Binding a local variable does not automatically create an ongoing reference to that variable. Use std::ref or std::cref when intentional reference semantics are required; the programmer must then ensure the referenced object remains alive longer than the binder’s use. The wrapper itself is an object with a concrete, implementation-defined callable type.
When the wrapper is invoked, value categories and callable qualifiers can affect which invocation is valid. A binder that holds move-only state may need to be invoked on an rvalue wrapper for operations that consume that state, while a reusable wrapper should not be designed around consuming its stored values on every call. The correct behavior follows the partial-function-application reference and the underlying callable’s requirements. This is important in event handlers, job queues and asynchronous work, where captured object lifetime must be understood before an operation is scheduled.
Compiler and feature-test checks
The feature-test macro __cpp_lib_bind_back has the value 202202L for the original C++23 interface. The library feature-test reference identifies that value and also lists a distinct newer interface associated with C++26. A project should check the relevant value in a suitable standard-library header and avoid asserting that std::bind_back exists merely because the compiler accepts other C++23 syntax. The GCC libstdc++ implementation documentation is another concrete source showing how its C++23 binder wraps the target and arguments.
For a toolchain without this feature, a small explicit lambda is a portable alternative. A callback such as auto minus_five = [](int x) { return subtract(x, 5); }; requires no bind_back. That equivalence also makes a useful unit test: for the same inputs, the binder and lambda should produce the same result.
Tradeoffs and common mistakes
- Reversing argument order:
std::bind_back(subtract, 5)(12)meanssubtract(12, 5), notsubtract(5, 12). - Assuming references: passing an ordinary lvalue stores a decayed copy unless intentional reference wrapping is used.
- Ignoring object lifetime: a reference wrapper does not keep an object alive and must not outlive its referent.
- Overgeneralizing compiler support: check the C++23 feature-test macro and the selected standard library.
- Using it for arbitrary argument rearrangement: binders operate on one end of the parameter list; use a lambda for more intricate calling conventions.
- Assuming performance benefits: readability and correct semantics come first; measure actual costs when the application is sensitive to allocation, copying or call overhead.
Knowledge check
- Which C++ standard first provides
std::bind_back? - In
std::bind_back(subtract, 5)(12), which argument reachesrhs? - What does
std::bind_front(subtract, 5)(12)return? - What macro can detect the presence of the C++23 binder?
- Does a binder extend the lifetime of an object referenced through
std::ref?
Answers: C++23; the bound value five; -7; __cpp_lib_bind_back at least 202202L; and no, the lifetime remains the caller’s responsibility.
References and connected lessons
The authoritative specifications are std::bind_front and std::bind_back on cppreference, the C++23 library-feature overview, the feature-test macro table, and GCC’s libstdc++ implementation reference. The video primary source is Jason Turner’s C++ Weekly episode 346. Continue into OSC++.034 — std::bind_front, OSC++.033 — std::invoke, OSC++.032 — std::function and callable objects, and std::variant and type-safe alternatives for adjacent standard-library concepts.
BitcoinVersus.Tech Editor’s Note: We volunteer daily to keep technical education accessible, accurate, and independently researched. If this lesson was useful, consider supporting the work with 5,000 satoshis using the original donation QR code below.

Open the QR code on a larger screen and scan it with your compatible mobile Bitcoin wallet. Verify the recipient address before sending.

Leave a Reply