Skip to content

Wiki

std::bind

About 12 min read

Existing English translations were reused. 4 current source blocks remain in Simplified Chinese, without triggering paid translation.

1.What problem does this section solve?

Sometimes you already have a function, but its parameters and target interface do not match:

  • Want to fix certain parameters in advance.
  • Want to adjust the order of parameters.
  • Want to bind a member function to an object, turning it into an ordinary callback.

std::bind An existing callable object can be adapted into a new callable object.

In modern C++, many bind scenarios can be written more clearly with Lambda. However, std::bind it still frequently appears in legacy projects, ROS2 examples, Boost.Asio callbacks, and member function adaptation, so it is worth mastering.

2.What is this feature?

std::bind 接收一个可调用对象和一组绑定参数,返回一个新的可调用对象。调用新对象时,占位符 _1、_2、_3 表示"调用时传进来的第 1、2、3 个参数"。

std::bind Requires the header file <functional>. The placeholder is in the namespace std::placeholders.

Syntax Meaning
std::bind(f, 10, _1) Fixed f The first parameter of 10
std::bind(f, _2, _1) Swap the order of the two parameters when calling
std::bind(&C::m, &obj, _1) Bind a member function to object obj
std::bind(f, std::ref(x), _1) Bind by reference, not by copy

3.Example code

3.1.Example 1: Fix some arguments of an ordinary function

#include <functional>
#include <iostream>
#include <string>

void print_student(const std::string& name, int age, int score)
{
    std::cout << name << " age=" << age << " score=" << score << "\n";
}

int main()
{
    // 程序从 main 函数开始执行,下面的语句会按顺序运行。
    using std::placeholders::_1;
    using std::placeholders::_2;

    print_student("Alice", 20, 95);

    // bind 会把函数和部分参数提前绑定成一个可调用对象。
    auto print_bob = std::bind(print_student, "Bob", _1, _2);
    print_bob(21, 88);

    auto print_charlie_score = std::bind(print_student, "Charlie", 22, _1);
    print_charlie_score(91);

    return 0;
}

Running result:

Alice age=20 score=95
Bob age=21 score=88
Charlie age=22 score=91

3.2.Example 2: Adjusting Parameter Order

The positions of the placeholders determine the order of the arguments received by the original function.

#include <functional>
#include <iostream>

void divide(int a, int b)
{
    std::cout << a << " / " << b << " = " << (a / b) << "\n";
}

int main()
{
    // 程序从 main 函数开始执行,下面的语句会按顺序运行。
    using std::placeholders::_1;
    using std::placeholders::_2;

    divide(10, 2);

    // bind 会把函数和部分参数提前绑定成一个可调用对象。
    auto swapped = std::bind(divide, _2, _1);
    swapped(2, 10);

    auto half = std::bind(divide, _1, 2);
    half(10);
    half(20);

    return 0;
}

Running result:

10 / 2 = 5
10 / 2 = 5
10 / 2 = 5
20 / 2 = 10

3.3.Example 3: Binding Member Functions

A non-static member function requires an object to be called.std::bind The second parameter is usually an object pointer, object reference, or smart pointer.

#include <functional>
#include <iostream>
#include <string>

class Printer
{
    std::string prefix_;

public:
    explicit Printer(const std::string& prefix) : prefix_(prefix) {}

    void print(int id, const std::string& text) const
    {
        std::cout << prefix_ << " #" << id << ": " << text << "\n";
    }
};

int main()
{
    // 程序从 main 函数开始执行,下面的语句会按顺序运行。
    using std::placeholders::_1;
    using std::placeholders::_2;

    Printer printer("LOG");

    // bind 会把函数和部分参数提前绑定成一个可调用对象。
    auto print_any = std::bind(&Printer::print, &printer, _1, _2);
    print_any(7, "ready");

    auto print_ok = std::bind(&Printer::print, &printer, _1, "ok");
    print_ok(8);

    return 0;
}

Running result:

LOG #7: ready
LOG #8: ok

Here &printer must remain valid during use of print_any and print_ok. If the bound callback will be stored somewhere longer-lived, smart pointers or more explicit lifetime management usually need to be considered.

3.4.Example 4: Comparison of bind and Lambda

For the same parameter adaptation task, Lambda is often more intuitive because the parameter names and call relationships are clearly written.

#include <functional>
#include <iostream>

int weighted_sum(int base, int x, int y)
{
    return base + x * 10 + y;
}

int main()
{
    // 程序从 main 函数开始执行,下面的语句会按顺序运行。
    using std::placeholders::_1;
    using std::placeholders::_2;

    // bind 会把函数和部分参数提前绑定成一个可调用对象。
    auto by_bind = std::bind(weighted_sum, 100, _1, _2);
    auto by_lambda = [](int x, int y) {
        return weighted_sum(100, x, y);
    };

    std::cout << "bind result = " << by_bind(3, 4) << "\n";
    std::cout << "lambda result = " << by_lambda(3, 4) << "\n";

    auto swapped_bind = std::bind(weighted_sum, 100, _2, _1);
    auto swapped_lambda = [](int x, int y) {
        return weighted_sum(100, y, x);
    };

    std::cout << "swapped bind result = " << swapped_bind(3, 4) << "\n";
    std::cout << "swapped lambda result = " << swapped_lambda(3, 4) << "\n";

    return 0;
}

Running result:

bind result = 134
lambda result = 134
swapped bind result = 143
swapped lambda result = 143

3.5.Example 5: bind copies arguments by default; use std::ref when a reference is needed

std::bind When saving ordinary parameters, they are copied by default. If you want to bind a reference, you must explicitly use std::ref or std::cref.

#include <functional>
#include <iostream>

void add_to(int& total, int value)
{
    total += value;
    std::cout << "inside total = " << total << "\n";
}

int main()
{
    // 程序从 main 函数开始执行,下面的语句会按顺序运行。
    int total = 0;

    // bind 会把函数和部分参数提前绑定成一个可调用对象。
    auto add_copy = std::bind(add_to, total, 5);
    add_copy();
    std::cout << "outside after copy bind = " << total << "\n";

    auto add_ref = std::bind(add_to, std::ref(total), 5);
    add_ref();
    std::cout << "outside after ref bind = " << total << "\n";

    return 0;
}

Running result:

inside total = 5
outside after copy bind = 0
inside total = 5
outside after ref bind = 5

3.6.Example 6: Using this in a member function to bind the current object

前面的示例是在类外部创建对象,再把对象地址 &printer 传给 std::bind。如果 std::bind 本身就在类的成员函数中使用,可以直接传入 this,表示把成员函数绑定到当前对象。

#include <functional>
#include <iostream>
#include <string>

class Robot
{
    std::string name_;

public:
    explicit Robot(const std::string& name) : name_(name) {}

    void on_message(int id, const std::string& text)
    {
        std::cout << name_ << " #" << id << ": " << text << "\n";
    }

    void demo()
    {
        using std::placeholders::_1;
        using std::placeholders::_2;

        auto callback = std::bind(&Robot::on_message, this, _1, _2);

        callback(7, "ready");
        callback(8, "running");
    }
};

int main()
{
    Robot robot("Cyber");
    robot.demo();

    return 0;
}

Running result:

Cyber #7: ready
Cyber #8: running

The most important thing here is:

auto callback = std::bind(&Robot::on_message, this, _1, _2);

Break it down:

Parameter Meaning
&Robot::on_message Member function to be called
this The current object calling this member function
_1 callback() The first parameter passed at call time
_2 callback() The second parameter passed at call time

A non-static member function cannot be called independently of an object.&Robot::on_message It only specifies "which member function to call"; it must also be told std::bind"on which Robot object to call it."

Outside the class, you can write:

std::bind(&Robot::on_message, &robot, _1, _2);

And within Robot its own member function,this is the pointer to the current object, so you can write directly:

std::bind(&Robot::on_message, this, _1, _2);

For example:

Robot robot("Cyber");
robot.demo();

After entering robot.demo(), the demo() inside this points to robot.

Therefore:

callback(7, "ready");

It can be approximately understood as:

this->on_message(7, "ready");

If the current object is exactly robot, it is equivalent to:

robot.on_message(7, "ready");

Therefore, this type of notation can be remembered as:

std::bind(&类名::成员函数, this, 参数...);

Where the second parameter this serves to:

Tell std::bind: When this member function is called later, call it on the current object.

This is also a very common way of writing in ROS2 and Boost.Asio, for example:

std::bind(&MyNode::callback, this, _1)

It indicates that MyNode::callback is bound to the current MyNode object, and then the first argument at call time is passed to callback.

Note that this is essentially a pointer. If the bound callback outlives the current object, calling the callback after the object is destroyed may access an already invalid this; therefore, object lifetime must still be considered in asynchronous callbacks.

4.Key syntax explanation

Syntax Description Notes
_1 The first parameter passed when calling a new function From std::placeholders
_2 The second parameter passed when calling a new function Can be used to adjust the order
Fixed value Written directly in bind parameter By default, it is copied and saved
&Class::method Member function pointer An object still needs to be bound afterward
this The current object pointer inside a member function Often used as the second parameter when binding a member function
std::ref(x) Bind by reference x If not written, std::ref is usually copied

5.How to choose between bind and Lambda

Scenario Recommendation
Simple fixed parameters Lambda or bind both work
The parameter relationships need to be read very clearly Lambda
Binding a member function to an old interface bind is very common, and a Lambda can also be used
Requires complex logic, conditional judgment Lambda
Reading old code or ROS2/Boost.Asio examples Must understand bind

一句话:新代码优先考虑 Lambda;遇到已有接口适配、旧项目代码、成员函数回调时,要能熟练读懂 std::bind。

6.Common Errors

  1. Forgot that the placeholder comes from std::placeholders.
  2. Reversed the order of _1 and _2 causing the argument order to be wrong.
  3. Forgot to bind the object when binding a member function.
  4. After binding an object pointer, the object is destroyed first while the callback is still using it.
  5. Assumed that bind stores arguments by reference by default. The default is copy; when a reference is needed, use std::ref.

7.Usage Recommendations

  1. In new code, parameter adaptation should first try Lambda.
  2. When reading ROS2, Boost.Asio, and old project code, you should be able to understand std::bind(&Class::method, this, _1, _2).
  3. When binding member functions, first consider the object's lifetime.
  4. When reference semantics are needed, explicitly write std::ref or std::cref.
  5. Do not write hard-to-read placeholder combinations just to use bind; clarity is more important than showing off.

8.Summary

  • std::bind 用来固定参数、调整参数顺序、绑定成员函数。
  • _1、_2 表示调用新可调用对象时传入的参数位置。
  • 成员函数中可以把 this 作为第二个参数,表示把成员函数绑定到当前对象。
  • bind 默认拷贝绑定参数,需要引用时用 std::ref。
  • 现代 C++ 中很多 bind 用法可以用 Lambda 替代。
  • 理解 bind 对阅读 ROS2、Boost.Asio 和旧 C++ 项目很有帮助。