std::function
std::function 是 C++11 引入的一个非常有用的模板类,它能够封装任何可以调用的目标(例如普通函数、函数指针、Lambda 表达式、成员函数或其他可调用对象),并使得它们可以像函数一样进行调用。它提供了一种灵活、统一的方式来处理各种类型的函数对象。
1. 基本概念
std::function 是一个可以存储任何符合指定签名的可调用对象的类型擦除封装器。它允许你通过统一的接口来调用不同类型的可调用对象,而无需关心其具体类型。
2. 语法
#include <functional>
std::function<返回类型(参数类型...)> 函数对象名;
3. 功能和用法
3.1. 普通函数指针
std::function 可以存储和调用普通的函数指针。
#include <iostream>
#include <functional>
void print_sum(int a, int b) {
std::cout << "Sum: " << a + b << std::endl;
}
int main() {
std::function<void(int, int)> func = print_sum;
func(3, 5); // 输出: Sum: 8
return 0;
}
3.2. Lambda 表达式
std::function 也可以封装 lambda 表达式,lambda 表达式提供了一个非常灵活的方式来创建临时函数对象。
#include <iostream>
#include <functional>
int main() {
std::function<int(int, int)> add = [](int a, int b) { return a + b; };
std::cout << add(3, 4) << std::endl; // 输出: 7
return 0;
}
3.3. 函数对象
std::function 可以存储自定义的函数对象(即实现了 operator() 的类)。
#include <iostream>
#include <functional>
struct Multiplier {
int operator()(int a, int b) const {
return a * b;
}
};
int main() {
std::function<int(int, int)> multiply = Multiplier();
std::cout << multiply(3, 4) << std::endl; // 输出: 12
return 0;
}
3.4. 成员函数指针
std::function 还支持封装成员函数,但需要注意它的使用方式。成员函数需要一个对象实例才能调用,所以你需要提供一个对象或者绑定到对象。
#include <iostream>
#include <functional>
class Printer {
public:
void print_message(const std::string& message) {
std::cout << message << std::endl;
}
};
int main() {
Printer printer;
std::function<void(const std::string&)> print_func =
std::bind(&Printer::print_message, &printer, std::placeholders::_1);
print_func("Hello, World!"); // 输出: Hello, World!
return 0;
}
3.5. 参数和返回值
std::function 是类型安全的,可以根据你给定的签名来确定可调用对象的类型,它会检查传入的参数和返回值类型是否匹配。
4. 主要操作
4.1. std::function 的赋值和调用
你可以将函数指针、lambda 或者函数对象赋给 std::function 变量。
使用 () 运算符调用存储的函数。
std::function<void()> func = some_function;
func(); // 调用 some_function
4.2. std::function 的重置
你可以使用 std::function::reset() 重置 std::function 对象,使其不再指向任何可调用对象。
std::function<void()> func = some_function;
func(); // 调用 some_function
func.reset(); // 重置,不再指向任何函数
4.3. std::function 的空检查
可以使用 std::function::operator bool() 来检查 std::function 是否为空。
std::function<void()> func;
if (func) {
func(); // 如果 func 非空则调用
} else {
std::cout << "No function to call." << std::endl;
}
5. 性能注意事项
std::function 是类型擦除的,意味着它会对不同的可调用对象进行动态分配和类型擦除,所以它的性能可能比直接使用普通函数指针或 lambda 表达式要差一些。尤其是在频繁调用时,可能会造成一定的性能开销。
6. 适用场景
- 回调函数:std::function 非常适合用于需要回调的场景,例如事件处理、异步编程等。
- 函数式编程:通过将函数作为参数传递,std::function 可以让代码更具灵活性和可扩展性。
- 事件驱动编程:可以用来处理事件驱动的框架,像 GUI 编程中按钮点击事件等。
- 结合std::unordered_map:std::unordered_map<std::string, std::function<void(par)>> mapping.
7. 示例:使用 std::function 实现简单的回调
#include <iostream>
#include <functional>
void my_function(int a) {
std::cout << "Callback called with: " << a << std::endl;
}
void invoke_callback(std::function<void(int)> callback) {
// 触发回调
callback(42);
}
int main() {
std::function<void(int)> callback = my_function;
invoke_callback(callback); // 输出: Callback called with: 42
return 0;
}
总结
std::function 是一个非常强大的工具,可以将不同类型的可调用对象统一封装并调用。它在需要高度灵活性的场景中非常有用,尤其是涉及回调和事件驱动的编程模式时。尽管它的性能可能略逊色于普通函数指针和直接的 Lambda 表达式,但它提供的高度抽象和灵活性使得它在许多高级用法中非常值得使用。