lambda表达式的完整声明如下:
[capture list](params list) mutable exception->return type{function body}
//capture list:捕获列表
/* [var]:以值的形式捕获
[&]:引用方式捕获
[=]:值捕获
//params list:参数列表
//mutable: 捕获列表可以修改
//exception:异常处理
//return type:返回值类型
看一道简单的例子:
#include<iostream>
using namespace std;
int main()
{
int a=9;
auto fun1=[=]()mutable{return ++a;};
cout<<fun1()<<endl;
cout<<a<<endl;
return 0;
}
输出的结果为:
以值传递,在lambda表达式中,修改a的值后,main()中a的值并未改变。说明传进去的a是一个副本。这也普通函数的参数传递中的值传递是一样。但是,普通函数按值传递,可以对得到的形参进行任意改变,如:++param,--param等,lambda表达式可以任意改变按值传递的参数的值吗?请看下面两道列子:
看一道难一点的列子:
#include<iostream>
using namespace std;
int main()
{
int a=9;
auto fun1=[=]{return a+1;};
auto fun2=[&]{return a+1;};
cout<<"fun1:"<<fun1()<<endl;
cout<<"fun2:"<<fun2()<<endl;
++a;
cout<<"++a执行之后的值"<<endl;
cout<<"fun1:"<<fun1()<<endl;
cout<<"fun2:"<<fun2()<<endl;
return 0;
}
程序运行之后结果如下:
为什么++a执行之后,fun1的值不是11呢?
lambda表达式中,a被视为常量。初始化一次后,保持不变。相反的,如果需要捕捉的值成为Lambda函数运行时的变量,则应该采用按引用方式进行捕捉。
再看一道例子:
#include<iostream>
using namespace std;
int main()
{
int a=9;
auto fun1=[=]{return ++a;};//代码片段1
auto fun2=[&]{return ++a;};//代码片段2
auto fun2=[=]()mutable{return ++a;};//代码片段3
return 0;
}
若运行程序,会有什么问题?
代码片段1:编译报错,error: increment of read-only variable ‘a’
代码片段2:正确运行
代码片段3:正确运行
默认情况下,Lambda函数总是一个const函数,mutable可以取消其常量性。按照规定,一个const的成员函数是不能在函数体内修改非静态成员变量的值。
总结:
1.若按值传递,表达式内部复制了一份捕获的变量;不论被捕获的变量如何改变(如++a),其已被捕获的值,在表达式内部保持不变;
2.若按引用传递,表达式内部的值,使用的就是被捕捉的变量的值;所以,被捕获的变量改变时,其内部的值也会改变;
3.按值传递,若想修改变量的值,则需要加mutable关键字;因为lambda默认是常函数;在一个常函数内部,只能修改static类型变量的值,不能修改非static类型变量的值。