一句话概括
std::bind 接收一个可调用对象和一组实参,返回一个新的可调用对象,用来固定部分参数 或调整参数顺序与数量 。头文件 <functional>,C++11 起提供。
最常用的两种用法
固定部分参数
cpp
#include <functional>
int add(int a, int b);
using namespace std::placeholders;
auto add10 = std::bind(add, 10, _1); // _1 = 新对象的第 1 个参数
add10(5); // 15
占位符 _1, _2, ... 标记"调用时再填"的位置,其余实参按值拷贝进返回对象。
调整参数顺序
cpp
auto swapped = std::bind(add, _2, _1);
swapped(3, 4); // add(4, 3) == 7
返回对象遵循 INVOKE 语义,可直接交给 std::function、std::thread 或标准算法。
绑定类成员
成员函数
cpp
struct Widget {
void draw(int layer);
};
Widget w;
auto d1 = std::bind(&Widget::draw, &w, _1); // 传对象指针
auto d2 = std::bind(&Widget::draw, std::ref(w), _1); // 传引用,不拷贝对象
成员函数隐含 this,所以第一个实参必须传对象:指针最常用,不想拷贝对象就用 std::ref。
成员变量
std::bind 同样接受成员变量指针,调用时返回该成员的引用,读、写都行:
cpp
struct Widget {
int value = 0;
};
Widget w;
auto value = std::bind(&Widget::value, &w);
value(); // 读:0
value() = 42; // 写:w.value == 42
auto get = std::bind(&Widget::value, _1); // 对象留到调用时再传
get(&w); // 42
要点:
- 绑定时必须给出对象(指针或
std::ref);对象为 const 时得到 const 引用,写入会编译失败。 - 返回的是成员引用,不延长对象生命周期,对象销毁后再调用即悬垂。
- 典型用途是泛型代码把"取成员"当可调用对象,例如按成员排序:
std::bind(&Widget::value, _1) < std::bind(&Widget::value, _2)。 - 日常代码里 lambda 更直观:
[&w] { return w.value; }。
bind 的短板:占位符数量有上限、需引入 std::placeholders;重载函数不能直接传入,须先转成函数指针;只能按位置绑定,参数个数或顺序写错时编译信息不友好。
常见坑
- 多余的实参被静默丢弃 :
add10(5, 99)合法,99直接忽略;实参不足则编译失败。 - 忘记
std::ref:修改的是 bind 内部保存的副本。 - 重载函数名歧义 :
std::bind(f, ...)无法推导,需写成std::bind(static_cast<int(*)(int)>(f), _1)。
结语
std::bind 是 C++11 的参数适配器:固定参数、重排顺序、绑定成员,一行完成。但表达力和可读性都不如 lambda,现代代码应优先 lambda。