std::function 用于存储任何符合指定签名的可调用对象,如普通函数、lambda、成员函数指针或 std::bind 结果;需严格匹配参数与返回类型,捕获局部变量时须注意生命周期,空对象调用抛 std::bad_function_call。

std::function 用来存什么函数?
std::function 是一个类型擦除的可调用对象包装器,能存任何符合签名的可调用物:普通函数、lambda、成员函数指针、std::bind 结果。它不自己执行逻辑,只提供统一接口调用。
关键点是「签名必须匹配」——比如声明为 std::function,就只能存接受 double、返回 int 的东西。传错类型编译直接报错,不是运行时崩溃。
- 不能存返回值或参数类型不匹配的函数(哪怕只差个
const或引用) - 捕获变量的 lambda 可以存进去,但要注意生命周期:如果 lambda 捕获了局部变量地址,而
std::function在函数外被调用,就是悬垂指针 - 空的
std::function调用会抛std::bad_function_call,用前建议判空:if (cb) cb(42);
std::bind 怎么绑定成员函数和参数?
绑定成员函数必须显式传入对象(或指针),因为 this 不是自动附带的。常见错误是写成 std::bind(&MyClass::func, arg1) —— 缺了对象实例,编译不过。
参数占位符用 _1、_2 等(需 #include ),它们代表调用时传入的位置参数;固定参数直接写在 std::bind 参数列表里。
立即学习“C++免费学习笔记(深入)”;
class Printer {
public:
void print(int x, const std::string& s) { std::cout << x << ": " << s << "\n"; }
};
Printer p;
auto bound = std::bind(&Printer::print, &p, 42, _1); // 固定 this 和第一个参数,_1 占位第二个
bound("hello"); // 输出 "42: hello"
- 用
std::ref(obj)绑定可变对象,避免拷贝;否则绑定的是副本,修改不影响原对象 - 绑定右值临时对象要小心:比如
std::bind(func, std::string("tmp")),临时对象在 bind 返回后就销毁,调用时读到的是垃圾 - C++17 起,
std::bind对完美转发支持有限,复杂场景推荐直接用 lambda
把 bind 结果塞进 function 为什么常出错?
最典型问题是签名不一致:比如成员函数是 void (int, int),但你绑定了两个固定参数,剩下 0 个可调用参数,那目标 std::function 类型就得是 std::function,而不是原函数签名。
另一个坑是 std::bind 返回类型不可名状(unspecified type),必须靠 std::function 接住,不能用 auto 存然后二次赋值——除非你只用一次,且不跨作用域。
std::functiontask = std::bind(&Printer::print, &p, 99, "done"); task(); // OK // 错误写法(类型不匹配): // std::function bad = std::bind(&Printer::print, &p, 99, "done"); // 编译失败:bind 结果调用时不接受 int 参数
- 如果需要“部分绑定 + 后续再补参数”,确保占位符数量和
std::function声明的参数个数一致 - 绑定后想改某个固定参数?做不到。
std::bind是一次性构造,要动态改就得换 lambda 或用对象封装状态
替代方案:什么时候该用 lambda 而不是 bind?
绝大多数简单回调场景,lambda 更直观、性能更好(无类型擦除开销)、生命周期更可控。只有两种情况才倾向 std::bind:
- 需要把同一个 bind 表达式多次赋给不同
std::function变量(lambda 每次定义类型都不同,无法赋值给同一变量) - 必须用占位符做参数重排,比如
std::bind(f, _2, _1)把调用顺序翻转——lambda 写起来啰嗦些
但注意:lambda 捕获 this 要明确写 [this],否则无法访问成员;而 std::bind 绑定成员函数时,this 是作为第一个参数传的,语义更接近传统 C 风格回调注册。
真正容易被忽略的是:std::function 的拷贝构造有潜在堆分配(内部存储大对象时),高频回调场景若对性能敏感,得评估是否值得用;而 lambda 若不捕获,通常能内联,std::bind 几乎不可能内联。









