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; //10
cout<<a<<endl; //9
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;}; //lambda表达式第一次初始化,a将被视为常量,保持不变。
auto fun2 = [&]{return a+1;};
cout<<"fun1:"<<fun1()<<endl; //10
cout<<"fun2:"<<fun2()<<endl; //10
++a;
cout<<"++a执行之后的值"<<endl;
cout<<"fun1:"<<fun1()<<endl; //9 + 1 = 10
cout<<"fun2:"<<fun2()<<endl; //10 + 1 = 11
return 0;
}
lambda表达式中,a被视为常量。初始化一次后,保持不变。相反的,如果需要捕捉的值成为Lambda函数运行时的变量,则应该采用按引用方式进行捕捉。
再看一道例子:
#include<iostream>
using namespace std;
int main()
{
int a = 9;
auto fun1 = [=]{return ++a;}; //代码片段1
auto fun2 = [&]{return ++a;}; //代码片段2
auto fun3 = [=]()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类型变量的值。