C++11的一大特性就是引入了Lambda表达式,并在后续的C++14进行了加强。 利用Lambda表达式,可以方便定义和创建匿名函数。一个Lambda表达式表示一个可调用单元,我们可以将其理解为一个未命名的内联函数。
其中——
capture list,捕获外部变量列表;paramters list,形参列表;mutable,用来说明是否可以修改捕获的外部变量;exception,抛出异常;return type,返回类型;function body,函数体。除此之外,还可以缺省部分声明构成不完整的Lambda表达式,常见的有以下几种——
序号格式1[capture list] (params list) -> return type {function body}2[capture list] (params list) {function body}3[capture list] {function body}其中——
格式1省略了mutable关键字和exception,声明的是一个const类型的表达式,这种表达式不能修改捕获列表中的值;格式2 省略了返回类型return type,但是编译器可以根据functionbody中的return语句推断出Lambda表达式的返回类型,如果没有return语句,默认为void类型;格式3中省略了参数列表,即无参的Lambda表达式。举个使用Lambda表达式的例子——
#include<iostream> #include<vector> #include<algorithm> using namespace std; int main(){ vector<int> v{12,52,67,87,34,95,16,48}; //使用格式3的Lambda表达式定义sort排序规则 sort(v.begin(),v.end(), [](int&a,int&b){return a<b;}); for(auto&elem:v){ cout<<elem<<" "; } return 0; }Lambda表达式可以使用其可见范围内的外部变量,但必须明确声明。主要通过中括号[]来捕获外部变量,比如——
#include<iostream> using namespace std; int main(){ int a = 100; auto f = [a]{cout<<a<<endl;}; f();// f相当于一个无参的函数调用 return 0; }这种方式有别于传统的函数参数,增加了语言使用的灵活性。 Lambda表达式的外部变量捕获有4种方式:值捕获、引用捕获、隐式捕获和混合捕获。
值捕获与函数传参数相似,都是按值传递,外部变量的改变不会影响表达式已捕获变量的值——
#include<iostream> using namespace std; int main(){ int a = 100; auto f = [a]{cout<<a<<endl;}; a = 200;// 此时改变a的值 f();// 依旧输出100,而不是200 return 0; }需要注意的是,捕获的外部变量是const的,无法修改。 如果需要修改,需添加mutable关键字,括号也不能省略,比如说——
#include<iostream> using namespace std; int main(){ int a = 100; auto f = [a]()mutable{cout<<++a<<endl;}; a = 200;// f(); return 0; }顾名思义,就是捕获一个外部变量的引用,只需要在捕获的外部变量前面加上一个&即可——
#include<iostream> using namespace std; int main(){ int a = 100; auto f = [&a]{cout<<a<<endl;}; a = 200;// 此时改变a的值 f();// 输出200 a = 300; f();//输出300 return 0; }有时候,捕获的变量比较多的情况,一一书写变量名,可能就会很麻烦。 针对这种情况,Lambda提供了一种隐式捕获的方法,让编译器自行推断需要捕获哪些变量。 我们只需要定义捕获的方式是值捕获还是引用捕获,这就是隐式捕获。 具体使用方法,举例如下——
#include<iostream> using namespace std; int main(){ int a = 100; int b = 200; int c = 300; int d = 400; auto f = [=]{ cout<<"a = "<<a<<endl <<"b = "<<b<<endl <<"c = "<<c<<endl <<"d = "<<d <<endl;};// 值捕获 f(); return 0; }只需要把=改成&,就变成引用捕获了,在此不再举例。
Lambda还支持以上几种方式的混合使用,具体语法,总结如下——
序号语法作用1[]不捕获任何外部变量2[args …]默认是值捕获的方式,如果需要引用捕获,需要单独在变量名前加&3[this]以值捕获的形式捕获this指针4[=]以值捕获的形式捕获所有外部变量5[&]以引用捕获的方式捕获所有的外部变量6[=,&x]变量x以引用捕获,其余值捕获7[&,x]变量x值捕获,其余引用捕获Lambda表达式的参数列表和函数的参数列表类似,但是又有所不同,具体表现为——
不支持默认参数列表不支持可变参数列表所有参数必须有参数名相同之处在于,Lambda表达式的参数列表同样可以作为局部变量看待,能够覆盖同名的全局变量。
