std::function是C++11引入的函数包装器模板,它提供了一种统一的方式来处理各种可调用对象。本质上,它是一个类型擦除容器,能够存储、复制和调用任何符合签名要求的可调用实体。
在传统C++中,函数指针虽然能指向特定函数,但存在严重局限性:
std::function通过模板参数明确声明函数签名(如std::function<int(float, string)>),在编译期就能确保类型匹配。当尝试存储不匹配的可调用对象时,编译器会直接报错。
关键特性:std::function对象可以像普通函数一样被调用,使用operator()语法,同时保持值语义(可以拷贝、赋值)。
典型的std::function实现采用"小对象优化"策略:
这种设计使得std::function在大多数场景下都能保持高效,同时不损失灵活性。
cpp复制#include <functional>
#include <iostream>
double multiply(double a, double b) {
return a * b;
}
int main() {
// 显式指定函数签名
std::function<double(double, double)> func = multiply;
// 自动推导函数签名(C++17起)
std::function func2 = multiply;
std::cout << func(3.14, 2.71) << std::endl;
return 0;
}
注意事项:
cpp复制void (*raw_func)(int) = [](int x) { /*...*/ };
std::function<void(int)> wrapped_func = raw_func;
虽然可以相互转换,但std::function提供了更多优势:
cpp复制std::function<int(int)> factorial = [](int n) {
return (n <= 1) ? 1 : n * factorial(n - 1); // 递归lambda
};
高级技巧:
cpp复制auto lambda = [](auto x, auto y) { return x + y; };
std::function<double(double, double)> func = lambda;
注意:泛型lambda需要明确指定std::function的模板参数。
cpp复制class Calculator {
public:
int add(int a, int b) { return a + b; }
};
Calculator calc;
auto bound_func = std::bind(&Calculator::add, &calc,
std::placeholders::_1,
std::placeholders::_2);
std::function<int(int, int)> func = bound_func;
最佳实践:
cpp复制class Button {
std::function<void()> onClick;
public:
void setHandler(std::function<void()> handler) {
onClick = std::move(handler);
}
void click() {
if(onClick) onClick();
}
};
这种设计模式在GUI框架和事件系统中广泛应用。
实测数据(GCC 11.2,-O3优化):
问题1:bad_function_call异常
cpp复制std::function<void()> empty_func;
empty_func(); // 抛出异常
解决方案:调用前检查empty()或operator bool()
问题2:生命周期问题
cpp复制std::function<void()> createFunc() {
int local = 42;
return [&local]() { /*...*/ }; // 悬垂引用!
}
解决方案:值捕获或使用shared_ptr管理状态
cpp复制template <typename F, typename G>
auto compose(F f, G g) {
return [=](auto x) { return f(g(x)); };
}
std::function<int(int)> f = [](int x) { return x * 2; };
std::function<int(int)> g = [](int x) { return x + 3; };
auto h = compose(f, g);
cpp复制class StateMachine {
std::function<void()> currentState;
public:
void transitionTo(std::function<void()> newState) {
currentState = std::move(newState);
}
void run() {
while(currentState) {
currentState();
}
}
};
cpp复制std::vector<std::function<double(double)>> transforms;
transforms.push_back([](double x) { return std::sqrt(x); });
transforms.push_back([](double x) { return x * x; });
for (auto& f : transforms) {
std::cout << f(2.0) << std::endl;
}
cpp复制using VariantFunc = std::variant<
std::function<void(int)>,
std::function<void(std::string)>
>;
VariantFunc v = [](int x) { /*...*/ };
std::visit([](auto&& f) { f(42); }, v);
在实际工程中,std::function最常见的应用场景包括:
掌握std::function的使用技巧,可以显著提升C++代码的灵活性和可维护性。建议从简单场景开始实践,逐步应用到更复杂的架构设计中。