std::function
是 C++11 引入的通用可调用对象包装器,用于存储、复制和调用任意符合特定函数签名的可调用对象(如函数、lambda、函数对象等)。以下是其核心要点及使用指南:
核心特性
-
类型擦除
可包装任意可调用对象,只要其调用签名与模板参数匹配。
例如:std::function<int(int, int)>
可存储普通函数、lambda、std::bind
表达式等,只要它们接受两个 int
参数并返回 int
。
-
灵活性
比函数指针更通用,支持成员函数、带状态的函数对象等。
#include <functional>
#include <iostream>
void print(int x) { std::cout << x << std::endl; }
struct Functor {
void operator()(int x) const { std::cout << x << std::endl; }
};
int main() {
std::function<void(int)> f1 = print; // 普通函数
std::function<void(int)> f2 = Functor(); // 函数对象
std::function<void(int)> f3 = [](int x) { // Lambda
std::cout << x << std::endl;
};
f1(42); // 输出 42
f2(42); // 输出 42
f3(42); // 输出 42
}
-
成员函数绑定
需结合 std::bind
或 Lambda 绑定对象实例:
class MyClass {
public:
void method(int x) { std::cout << x << std::endl; }
};
int main() {
MyClass obj;
// 使用 std::bind
std::function<void(int)> f1 = std::bind(&MyClass::method, &obj, std::placeholders::_1);
// 使用 Lambda
std::function<void(int)> f2 = [&obj](int x) { obj.method(x); };
f1(42); // 输出 42
f2(42); // 输出 42
}
使用注意事项
-
空状态检查
调用空的 std::function
会抛出 std::bad_function_call
。
检查是否可调用:
std::function<void(int)> f;
if (f) { // 检查是否非空
f(42);
}
- 性能开销
存在类型擦除带来的间接调用开销(类似虚函数调用),通常适用于非性能敏感场景。
对比模板的高效性:
template <typename Callable>
void call(Callable&& f, int x) { f(x); } // 无运行时开销,适合高频调用
- 类型兼容性
参数和返回类型支持隐式转换:
void func(double x) { std::cout << x << std::endl; }
std::function<void(int)> f = func;
f(42); // int 隐式转为 double,输出 42.0
- 不可比较性
std::function
对象无法直接比较是否包装同一可调用对象:
std::function<void()> f1 = [] {};
std::function<void()> f2 = [] {};
// if (f1 == f2) { ... } // 错误:operator== 未定义
适用场景
-
回调机制
事件处理、异步操作等需动态注册回调的场景:
class Button {
public:
void setOnClick(std::function<void()> onClick) {
onClick_ = std::move(onClick);
}
void click() { if (onClick_) onClick_(); }
private:
std::function<void()> onClick_;
};
-
策略模式
运行时动态切换算法或行为:
class Processor {
public:
using Algorithm = std::function<int(int, int)>;
void setAlgorithm(Algorithm algo) { algo_ = algo; }
int process(int a, int b) { return algo_ ? algo_(a, b) : 0; }
private:
Algorithm algo_;
};
-
函数组合
实现高阶函数(如函数适配器):
auto compose(std::function<int(int)> f, std::function<int(int)> g) {
return [f, g](int x) { return f(g(x)); };
}
总结
- 优势:类型安全、灵活性高,适合需要动态绑定可调用对象的场景。
- 局限:运行时开销较高,无法直接比较包装的内容。
- 替代方案:在性能关键代码中,优先考虑模板或函数指针。