lambda表达式、std::function与std::bind
lambda表达式
lambda表达式是C++11引入的特性,允许定义匿名函数,简化参数的传递
1 | |
capture捕获列表
用于捕获lambda表达式所处的作用域中的外部变量[]不捕获任何变量[]按引用所有外部捕获变量[=]按值捕获所有外部变量[=, &a]按值捕获所有外部变量,同时按引用捕获变量a[a]按值捕获变量a[this]捕获当前对象的this指针
params参数列表opt函数选项,例如mutable(可以修改按值捕获的变量)ret返回类型
std::function
可调用对象
可调用对象是指可以被调用的实体,只要满足以下条件之一即可称为调用对象
- 函数指针
- 具有
operator()成员函数的类对象 - 可以被转换为函数指针的类对象
- 类成员函数指针
lambda表达式std::bind表达式或其他函数对象
std::function
std::function是一个通用的函数封装器,可以存储、复制和调用任何可调用对象。其模板参数用于指定函数的签名,例如
1
std::function<void(int)> f;
中的模板参数void(int)表示接受一个参数为int且返回void的可调用对象。
示例
1 | |
std::function如果为空,在调用时会抛出std::bad_function_call异常std::function常用语回调函数和事件处理等场景
std::bind
std::bind 用于将可调用对象与其参数绑定,生成一个新的可调用对象。它的主要作用有:
- 将可调用对象与参数绑定为另一个
std::function。 - 将
n元可调用对象转换为m元可调用对象(m<n),即部分应用。
示例
1 | |
- 使用占位符(如
_1、_2)可以灵活地重排序参数。
例如_2就表示这是绑定后的可调用对象的第2个参数 std::bind常用于延迟调用和参数部分应用。
std::bind和lambda表达式
实际上,std::bind能做的,lambda都能做,并且更加优雅。
例如
- 绑定参数
这是最常见的用法。std::bind 将一个或多个参数预先绑定到一个函数上。
std::bind写法:1
2
3
4
5void print_sum(int a, int b) {
std::cout << a + b << std::endl;
}
auto print_10_plus_5 = std::bind(print_sum, 10, 5);
print_10_plus_5(); // 输出 15lambda等价写法:1
2auto print_10_plus_5_lambda = [](){ print_sum(10, 5); };
print_10_plus_5_lambda(); // 输出 15
- 使用占位符 (placeholders)
std::bind 使用占位符(如 _1, _2)来指定调用时提供的参数应该放在哪个位置,甚至可以重排参数顺序。
std::bind写法:1
2
3
4
5
6
7using namespace std::placeholders; // for _1, _2
void print_ordered(int a, int b, int c) {
std::cout << a << ", " << b << ", " << c << std::endl;
}
// 创建一个函数,它接受两个参数,并把它们作为第一和第三个参数传给 print_ordered,同时第二个参数固定为 100
auto f_bind = std::bind(print_ordered, _1, 100, _2);
f_bind(1, 99); // 输出 1, 100, 99lambda等价写法:lambda通过自己的参数列表来自然地实现这一点,而且可读性更高。1
2auto f_lambda = [](int x, int z){ print_ordered(x, 100, z); };
f_lambda(1, 99); // 输出 1, 100, 99
- 绑定成员函数
std::bind 可以用来绑定类的成员函数。
std::bind写法:1
2
3
4
5
6struct MyClass {
void member_func(int val) { std::cout << "Value: " << val << std::endl; }
};
MyClass instance;
auto bound_member = std::bind(&MyClass::member_func, &instance, _1);
bound_member(42); // 输出 "Value: 42"lambda等价写法:
通过捕获实例指针或引用,lambda可以更直观地实现。1
2
3MyClass instance;
auto lambda_member = [&instance](int val){ instance.member_func(val); };
lambda_member(42); // 输出 "Value: 42"
但lambda表达式能做的std::bind却不一定能做,例如
在原函数基础上添加额外逻辑:
lambda的函数体可以包含任意复杂的代码,而std::bind只能进行函数调用。泛型编程:C++14 引入了泛型
lambda,参数类型可以用auto,这是std::bind无法做到的。1
auto generic_lambda = [](auto x, auto y) { return x + y; };此外,现代编译器对
lambda的优化非常出色,通常能生成比std::bind更快的代码。
lambda表达式、std::function与std::bind
https://guts.homes/2025/06/22/lambda/