第 18.13 節

std::bind

0瀏覽次數0訪問次數--跳出率--平均停留

What problem does this section solve?

Sometimes you already have a function, but its parameters don't match the target interface.

  • I want to predefine certain parameters.
  • I'd like to adjust the order of the parameters. Which system or tool are you working with—such as a microcontroller, Robot Operating System, or something else? I can help you rearrange the parameters once I know the context.
  • 想把成员函数绑定到某个对象上,变成普通回调。

std::bind can adapt existing callable objects into new callable objects.

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

What is this feature?

std::bind takes a callable object and a set of bound parameters, returning a new callable object. When invoking the new object, the placeholders _1, _2, and _3 represent the first, second, and third arguments passed at call time.

std::bind requires the header file <functional>, with the placeholder in the namespace std::placeholders.

writing methodMeaning
std::bind(f, 10, _1)Set the first parameter of f to 10.
std::bind(f, _2, _1)Swap the order of the two parameters when calling.
std::bind(&C::m, &obj, _1)Bind member functions to objects obj
std::bind(f, std::ref(x), _1)Bind references, not copies.

Example code

Example 1: Fixed partial arguments of a regular 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;
}

Results

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

Example 2: Adjust Parameter Order

The position of placeholders determines the order of parameters 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;
}

Results

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

Example 3: Binding Member Functions

Non-static member functions require an object to be called. The second parameter of std::bind is typically 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;
}

Results

LOG #7: ready
LOG #8: ok

This &printer must remain valid throughout the use of print_any and print_ok. If the bound callback is to be saved for a longer duration, it is generally necessary to consider smart pointers or more explicit lifecycle management.

Example 4: Comparison between bind and Lambda

For the same parameter adaptation task, Lambda tends to be more intuitive, since both parameter names and call relationships are clearly written out.

#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;
}

Results

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

Example 5: By default, bind copies its parameters, so use std::ref when a reference is needed.

std::bind copies parameters by default when saving. If you want to bind references, 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;
}

Results

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

Key Grammar Explanation

writing methodExplanationPrecautions
_1The first parameter passed when calling a new functionFrom std::placeholders
_2The second parameter passed when calling a new function.can be used to adjust the order
constantWrite directly into the bind parameter.It will be copied and saved by default.
&Class::methodpointer to member functionStill need to bind objects later.
std::ref(x)Bind by reference xNot writing std::ref usually involves copying.

How to choose between bind and Lambda

SceneRecommendation
Simple fixed parametersLambda or bind are both fine.
The parameter relationships need to be understood clearly.Lambda
Binding member functions to legacy interfaces can be tricky due to how member functions implicitly capture the this pointer. Below are some common approaches to handle this scenario:

1. Use a Static Member Function with a Global/Object Map

class MyClass {
public:
    void callback(int data) { /* ... */ }

    static void staticCallback(int data) {
        // Retrieve the object instance (e.g., via a map or static member)
        MyClass* instance = getInstance();
        instance->callback(data);
    }
};

// Example mapping mechanism (simplified)
MyClass* MyClass::getInstance() {
    static MyClass instance;
    return &instance;
}

// Register the static function with the legacy interface
legacyRegister(MyClass::staticCallback);

2. Use a Free Function with a Capturing Lambda (C++11+)

MyClass* obj = new MyClass();

// Wrap the member function in a lambda
legacyRegister([obj](int data) {
    obj->callback(data);
});

// Remember to manage object lifetime to avoid dangling pointers.

3. Use std::bind (C++11)

MyClass obj;
auto boundFunc = std::bind(&MyClass::callback, &obj, std::placeholders::_1);
legacyRegister(boundFunc);

Key Considerations

  • Lifetime Management: Ensure the bound object outlives the callback usage.
  • Thread Safety: If callbacks occur across threads, synchronize access accordingly.
  • Function Signature: Match the expected signature of the legacy interface (argument types, return type).

Choose the method that best fits your project's constraints and codebase style. For simple cases, a lambda with explicit capture is often the most readable solution.|bind is very common, and you can also use Lambda.| |Requires complex logic and conditional judgment.|Lambda| |Reading old code or ROS2/Boost.Asio examples|Must understand bind|

In a word: new code prioritizes Lambda; when adapting existing interfaces, legacy project code, or member function callbacks, need to be adept at interpreting std::bind.

Common Errors

  1. Forgot where the placeholder comes from std::placeholders.
  2. mistook the order of _1 and _2, resulting in incorrect actual parameter sequence.
  3. Forgot to bind the object when binding member function.
  4. After binding the object pointer, the object is destroyed first while the callback is still in use.
  5. By default, bind saves parameters by reference. The default is to copy; when a reference is needed, use std::ref.

使用建议

  • 明确目标:在开始前确定您的具体需求,以便选择最合适的工具或教程。
  • 充分利用资源:参考官方文档、教程和博客,这些资料能帮助您快速上手并解决问题。
  • 实践应用:通过动手操作项目或编写代码来巩固学习成果,提升实际操作能力。
  • 问题解决:遇到困难时,查阅参考资料或寻求社区支持,逐步培养独立解决问题的能力。
  • 分享经验:完成项目后,可以撰写文章或博客分享心得,帮助其他学习者。

如果需要针对特定领域(如单片机、机器人或环境搭建)的进一步建议,请提供更多信息,我将为您细化内容。

  1. In the new code, parameter adaptation prioritizes attempting Lambda.
  2. When reading ROS2, Boost.Asio, and legacy project code, it's essential to understand std::bind(&Class::method, this, _1, _2).
  3. When binding member functions, first and foremost consider the object lifetime.
  4. When you need to refer to semantics, explicitly write std::ref or std::cref.
  5. Avoid creating hard-to-read placeholder combinations just to use bind. Clarity is more important than showing off.

Summary

  • std::bind is used to fix parameters, adjust their order, and bind member functions.
  • _1 and _2 indicate the parameter positions passed when calling the new callable.
  • bind copies bound parameters by default; use std::ref when referencing is needed.
  • In modern C++, many bind use cases can be replaced with Lambdas.
  • Understanding bind is quite helpful for reading ROS2, Boost.Asio, and legacy C++ projects.
音乐页