C++ lambda表达式
lambda表达式组成
[捕获列表](参数列表)->返回类型{函数体}
- 参数列表和返回类型可以省略,但捕获列表和函数体必须包含;
- 捕获列表通常为空,返回类型必须使用尾置返回;
- 例:
auto f = []{return 42;};
捕获列表
- 只用于局部非static变量
- 值捕获:捕获的变量值是在lambda表达式创建时变量的拷贝,而不是调用时的拷贝
void fcn1(){
int v1=42;
auto f=[v1]{return v1;};
v1=0;
auto j=f(); //j=42
}
- 引用捕获:捕获的是变量的引用,而不是拷贝。
void fcn2(){
int v1=42;
auto f=[&v1]{return v1;};
v1=0;
auto j=f(); //j=0
}
隐式捕获
- 使得编译器自己推断捕获列表,我们可以告诉编译器使用值捕获还是引用捕获:
[=]
采用值捕获;[&]
采用引用捕获;
显式捕获隐式捕获混用
- 捕获列表的第一个元素必须是
=
或者&
; - 显式捕获必须使用和隐式捕获不同的方式:
[=, var]
:var必须为引用捕获[&,var]
:var必须为值捕获
可变lambda
- 在值捕获的lambda表达式中,如果想要改变该变量的值,必须加上关键字mutable:
void fcn3(){
int v1=42;
auto f=[v1]() mutable {return ++v1;};
v1=0;
auto j=f();//j=43
}
- 在引用捕获中,能否改变捕获变量的值取决于该变量是否是const:
void fcn4(){
int v1=42;
auto f=[&v1](){return ++v1;};
v1=0;
auto j=f();//j=1
}
捕获列表的作用:
当可调用对象只能接受一个参数,但是需要两个或者多个参数才能完成操作时,这个时候lambda表达式的参数列表只能有一个,哪另外一个参数怎么传进来呢?就是靠捕获列表;
如果要使用函数来替代lambda表达式的功能,碰到这种只能传入单一参数的情况,还有一种解决方式,使用标准库bind函数。
bind函数 (functional头文件)
- 先定义一个可以传入两个或多个参数完成操作的函数
bool func1(int a1,int a2){
return a1>=a2;
}
- 然后使用bind函数将这个func1函数再封装一层:
auto func2=bind(func1,_1,6);
- 其中
_1
_2
…是占位符,代表func2的第一个、第二个…参数,我们这里我们将func1的第二个参数绑定为6,这样,func2就变成了一个只需要传入一个参数的函数(可调用对象);func2传入的参数类型和返回类型和func1完全一样。 - 使用占位符需要使用std::placeholders命名空间:
using namespace std::placeholders;
使用bind可以重排参数顺序
- 函数g只需要传入两个参数,
g(m,n)
,则m
和n
会分别传入_1
和_2
的位置:
auto g=bind(f,a,b,_2,c,_1);
即g(m,n)
等价于f(a,b,n,c,m)