1. 介绍
[captrue list](parameter list)-> return type {function body}
capture list:捕获表达式所在函数的局部变量,用于在function body函数体内使用(不可忽略)
parameter list:参数列表,传入的参数(可忽略)
return type:表达式返回类型(可忽略)
function body:函数体(不可忽略)
Lambda表达式是一种可调用对象,它的调用和普通函数相同,都是调用运算符
Lambda表达式原理:编译器会在表达式定义时生成一个对应的新的类类型,并在调用它的地方生成一个对象,捕获的变量就相当于它的数据成员。
auto f=[]() {return 42;}
cout<<f()<<endl; //42
void printf()
{
for_each(vec.begin(),vec.end(),[](const string &s){cout<<s<<" ";});
}
void compare()
{
int length;
sort(vec.begin(),vec.end(),[length](int i){return i<length;});
}
2. 捕获
2.1 值捕获(显式捕获)
Lambda表达式值捕获:[capture value] (......)-> return type {function body}
与传值参数类似,采用值捕获的前提是变量可以拷贝,与传参不同的是,被捕获变量的值是在lambda创建时拷贝,而不是调用时拷贝。
注意:以值捕获的变量在Lambda表达式里默认带有const属性,不能修改。
2.2 引用捕获(显式捕获)
Lambda表达式引用捕获:[&capture value] (......)-> return type {function body}
引用捕获的变量必须保证在Lambda表达式执行时,引用所指向的变量还存在,并且是所期望的值。
2.3 隐式捕获
隐式捕获:由编译器自己根据表达式中函数体里的代码来推断出我们需要哪些变量。
[&] | 采用引用捕获方式,lambda体中所使用的来自函数的变量都采用引用方式使用 |
[=] | 采用值捕获方式,lambda体中所使用的来自函数的变量都采用拷贝方式使用 |
[&,capture value list] | 采用隐式捕获和显式捕获混合方式,capture value list是一个以逗号分割的以值捕获形式的参数列表。 |
[=,&capture value list] | 采用隐式捕获和显式捕获混合方式,&capture value list是一个以逗号分割的以引用捕获形式的参数列表。 |
注意:当使用混合方式时,隐式捕获必须写在第一位,并且要和显示捕获的捕获方式相反,比如:上文[&,capture value list],第一个使用的隐式捕获&,那么后面的显示捕获必须使用值捕获的方式来写,而不能使用引用捕获&。
3. 可变lambda
默认情况下,值捕获的变量,lambda里不能改变它的值(同上),如果我们希望能改变一个被捕获的变量的值,就必须在参数列表首加上关键词mutable,所以,可变lambda能省略参数列表。
auto f=[v]() mutable {return ++v;};
4. 指定lambda返回类型
lambda表达式默认情况下,如果没有指定返回类型,且只包含一个单一的return语句的话,编译器会根据return的类型来判断返回类型。但如果有多个return语句,则必须要指定返回类型,不然会报错。
auto f = (=)[]{return v;}; //true
auto f = (=)[]{if(v<0) return -v; else return v;}; //error,有两个返回语句,且没有指定返回类型,编译器一开始没看到返回语句会默认返回void,但是看到了返回语句发现又返回的是int类型,有冲突