How std::bind Associates Arguments in C++
In C++, std::bind acts as a function adapter that
generates a callable wrapper around an existing function, member
function, or functor. It associates arguments with specific target
parameters by either capturing fixed values at the time of binding or
dynamically routing runtime arguments using placeholder tokens. This
mechanism allows developers to partially apply functions, reorder
parameters, or adapt signatures to fit specific interface
requirements.
Fixed Arguments
When a value or variable is passed directly into
std::bind, it is stored inside the resulting wrapper
object. By default, std::bind stores these values by value,
making copies or moving them into the wrapper. When the returned
function object is invoked, these stored values are automatically passed
to their corresponding parameter positions in the target function.
To pass an argument by reference rather than by value, you must wrap
the variable in std::ref or std::cref. Without
these wrappers, any changes made to the original variable will not be
reflected inside the bound function call, and modifications made by the
target function will not alter the original variable.
Dynamic Arguments via Placeholders
To leave parameter slots open for values provided at call time,
std::bind uses placeholders defined in the
std::placeholders namespace, such as _1,
_2, _3, and so on.
The association works through a positional mapping system:
- The index of the placeholder (
_N) specifies the position of the argument passed when calling the generated wrapper. For example,_1refers to the first argument passed to the wrapper, and_2refers to the second. - The position of the placeholder inside
std::binddictates which parameter of the underlying target function receives that value.
Reordering and Discarding Arguments
Because placeholders decouple the caller's argument list from the target function's signature, arguments can be rearranged or discarded entirely.
Consider the following function:
void display(int a, int b, int c);Using std::bind, the parameters can be mapped in various
ways:
using namespace std::placeholders;
// Binds 'b' to a constant value of 42.
// Maps wrapper argument 1 to 'a' and wrapper argument 2 to 'c'.
auto fn1 = std::bind(display, _1, 42, _2);
fn1(10, 20); // Calls display(10, 42, 20)
// Inverts the caller's arguments.
// The first wrapper argument maps to 'c', and the second maps to 'a'.
auto fn2 = std::bind(display, _2, 100, _1);
fn2(5, 15); // Calls display(15, 100, 5)
// Ignores extra arguments.
// Only the first argument provided to fn3 is used; any subsequent arguments are ignored.
auto fn3 = std::bind(display, _1, 0, 0);
fn3(7, 8, 9); // Calls display(7, 0, 0)Member Functions and the
this Pointer
When binding non-static member functions, the first argument to the
underlying function must always be an instance of the class (the
this pointer or object reference). std::bind
associates the target instance either by passing an object pointer or
reference directly as a fixed argument, or by supplying a placeholder
like _1 to require the caller to provide the instance at
invocation time.