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, _1 refers to the first argument passed to the wrapper, and _2 refers to the second.
  • The position of the placeholder inside std::bind dictates 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.