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} |
其中——
举个使用Lambda表达式的例子——
#include
#include
#include
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
using namespace std;
int main(){
int a = 100;
auto f = [a]{cout<<a<<endl;};
f();// f相当于一个无参的函数调用
return 0;
}
这种方式有别于传统的函数参数,增加了语言使用的灵活性。
Lambda表达式的外部变量捕获有4种方式:值捕获、引用捕获、隐式捕获和混合捕获。
值捕获与函数传参数相似,都是按值传递,外部变量的改变不会影响表达式已捕获变量的值——
#include
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
using namespace std;
int main(){
int a = 100;
auto f = [a]()mutable{cout<<++a<<endl;};
a = 200;//
f();
return 0;
}
顾名思义,就是捕获一个外部变量的引用,只需要在捕获的外部变量前面加上一个&即可——
#include
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
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表达式的参数列表同样可以作为局部变量看待,能够覆盖同名的全局变量。