C++11中提出了lambda表达式的概念,简单地说,就是创建临时的匿名函数。
一、声明lambda表达式
标准格式如下:
[capture list] (params list) mutable exception-> return type { function body }
1.[capture list]:这代表捕获的外部变量列表,可以捕获当前作用域下,所有可见的外部变量。只有被捕获的外部变量,才可以在{ function body }中使用。
2.(params list):这代表形参列表,lambda构造了一个匿名函数,(params list)就是函数的形参列表,但是注意,不能写默认参数值。当函数是空参数列表时,可以不写。
3.mutable:用来说明是否可以修改捕获的变量。
4.exception:异常设定。
5.return type:函数的返回类型,可以不写,在不调用转换构造函数的前提下,编译器可以根据{ function body }中的return语句进行推导。
6.{ function body }:函数体。
上述的大部分内容可以省略,最最最简单的lambda表达式:
[]{};
二、捕获外部参数
1、通过[]捕获外部参数。只有被捕获的外部参数,方可在{ function body }中使用。
例如:
int main() {
int a{1};
auto f1 = [a]{return a;}; //捕获了变量a,可以在函数体中使用;
auto f2=[]{return a;}; //error,没有捕获变量a,不可以在函数体中使用
return 0;
}
2、值捕获与引用捕获
上述例子中是值捕获,可以使用被捕获变量的值,但是不能改变其值。
int main() {
int a{1};
auto f1 = [a]{return a++;}; //error,不能改变值捕获变量
return 0;
}
可以采用引用捕获的方式,在被捕获的变量前+&即可。
int main() {
int a{1};
auto f1 = [&a]{return a++;};
f1();
cout<<a;
return 0;
}
输出2.
3、全局隐式捕获
对于当前作用域所有可见的外部变量,[=]表示全局值捕获,[&]表示全局引用捕获。
4、混合捕获
大部分情况如下:
(1)[]: 不捕获任何外部变量。
(2)[变量名, …]: 默认以值得形式捕获指定的多个外部变量(用逗号分隔),如果引用捕获,需要显示声明(使用&说明符)。
(3)[this]: 以值的形式捕获this指针。
(4)[=]: 以值的形式捕获所有外部变量。
(5)[&]: 以引用形式捕获所有外部变量。
(6)[=, &x]: 变量x以引用形式捕获,其余变量以传值形式捕获。
(7)[&, x]: 变量x以值的形式捕获,其余变量以引用形式捕获。
5、mutable 关键字
假如我们想修改被捕获的外部参数,但是不想影响到lambda表达式外部的值,该怎么办呢?
可以采用mutable关键字+值捕获的方式。
int main ( )
{
int a = 123;
auto f = [a]()mutable { cout << ++a; }; // 不会报错
cout << a << endl; // 输出:123
f(); // 输出:124
return 0;
}
三、lambda表达式的类型
lambda表达式的类型是独有的,可以看作是仿函数,所以可以用std::function 和 std::bind存储:
std::function<int(int)> f1 = [](int a){ return a; };
四、lambda表达式的作用
看到这里,lambda表达式好像没什么用。一般匿名函数要配合特定的库函数才有用。比如在JAVA里面,lambda表达式要配合streamAPI才有用。在C++里面,lambda表达式主要配合STL的算法与容器才有用。
比如数组求和:
int main ( )
{
vector<int> v= {1,2,5,9,52,6,3,14};
int sum=0;
for_each(v.begin(),v.end(),[&sum](int a){sum+=a;});
cout<<sum;
}