lambda函数也称为匿名函数.即时即用函数,可以在使用它们的地方定义它们
比如计算一个数组的元素的总和,我们可以这样:
#include<iostream>
#include<algorithm>
using std::cout;
using std::endl;
using std::for_each;
int main()
{
int a[10]={1,3,2,5,4,6,9,7,0,8};
int sum=0;
for_each(a,a+10,[&sum](int n){sum+=n;});
cout<<sum<<endl;
return 0;
}
lambda函数使用起来很方便,因为它们比标准命名的函数紧凑
lambda函数的基本语法
①[闭包](参数){语句组}
#include<iostream>
#include<algorithm>
using std::cout;
using std::endl;
using std::for_each;
int main()
{
auto f = []() {cout<<"lambda";};
f();
return 0;
}
下面这个lambda式子隐式返回的是int类型:
#include<iostream>
using namespace std;
int main()
{
int num = 666;
auto fun = [num](int n){return num+n;};
cout<<fun(5)<<endl;
return 0;
}
在此语法中,编译器隐式确定返回类型(从定义范围内的return语句的类型确定,如果有的话).或者也可以明确指定return类型:
②[闭包](参数)-> 返回类型 {语句组}
在方括号内,闭包(可选的变量列表)可以为空
(参数)是一个参数列表,就像在任意其他函数中(如 int max(int x,int y)中的x,y)一样.语句组包含定义该lambda实现的主体.
A式:[ ](int a,int b) {return a+b;};
B式:[ ](int a,int b) -> int {return a+b;};
上面是一个简单的lambda函数的例子, 这个函数有两个整形参数并返回它们的和.它们看起来就像一个简单的传统函数,除了方括号[ ],代替函数名出现,另外,除了返回类型,语法也几乎相同;返回类型可以被明确的指定,如B式,也可不指出返回类型,如A 式(返回类型隐式的(int))
[ ](int n){for(int i=0;i<n;++i)cout<<i<<endl;}
上面的例子是取一个整数参数n,并打印1到n的值.
[ ](int n)
{
for(int i=0;i<n;++i)
cout<<i<<endl;
}
哈哈 ,是不是很像命名函数啊
上面的函数类型是void,因为没有返回值.同样.你始终可以明确给出lambda式子想要的返回值类型,如下面的这个例子
[ ]( )->double{return 10;}//明确指定double类型
返回值类型为double,他会把返回值10转换为double,否则是个隐式作为整数返回.
上式等价于
[ ] ( ) {return 10.0;};
使用lambda函数的最简单方法之一是将其储存在一个变量(在c++11中通常是auto类型)中,然后像使用一个函数名一样使用该变量.
如
int i,j;
i=1,b=2;
auto f =[](int a,int b){return a+b;};
cout<<f(i,j)<<endl;
需要注意的是lambda式子最后的分号是必须的.否则报错.
error: expected ‘,’ or ‘;’ before ‘f’
auto f =[ ](int a,int b){return a+b;}; <-这个小分号
介绍完简单的我们看一下较为复杂的中括号部分,也就是闭包部分
我们列出lambda式子的一般样式
[闭包] (参数) -> 类型 {语句组};
闭包是被lambda函数捕获的变量的列表,允许lambda函数捕捉的变量是指在代码周围,但在lambda区域外声明的变量.(有点像别人让你吃苹果,人家给你放到手里你才敢吃)
这个意思通过一个例子解释,假设在一个块内出现的lambda函数也声明了一个名为my_id的变量,如果my_id被捕获,那么该lambda可以在内部引用my_id,而不必把my_id作为参数来传递.
[my_id] (int n) {return my_id+n;}
lambda函数返回my_id(在代码周围声明的一个变量)和n(传递给函数的一个参数)的总和.
int my_id = 5000;
auto fun =[my_id](int n){return my_id+n;};
cout<<fun(5)<<endl;
cout<<fun(10)<<endl;
上式定义了一个lambda函数,保存它,然后调用 它两次.
在这种情况下,只有一个参数n被声明:
它用来在第3个语句中传递值5,并在第4个语句中传递值10.
因为my_id既不是一个参数,也不是在lambda内声明的一个局部变量,也不是全局变量,所以它必须被捕获才能进行访问.(送到手里苹果才敢吃)
苹果分(①情况)给没给(②③情况)
如果给了就会分,你真吃(咬一口(改变))和假吃(闻闻(不改变))两种情况.
前面的示例访问但不改变my_id的值.为了使lambda函数能可以改变my_id值,my_id必须引用(&)捕获.
[&my_id](int n){my_id+=n;return my_id;}
①[ ]//苹果没给
没有变量被捕获,这个lambda函数的定义仅可以引用其自身的参数,局部变量和全局变量.它不能引用在lambda以外的局部变量.
#include<iostream>
#include<algorithm>
using std::cout;
using std::endl;
using std::for_each;
int main()
{
int a=0,b=0,x=10,y=20,z=1;
auto f = [&a,&b,x,y](int n)
{
a=x+z;
b=y+n;
};
f(100);
cout<<"a is now"<<a<<endl;
cout<<"b is now"<<b<<endl;
return 0;
}
就像z这个苹果没放到你手里,你硬要吃.
编译器会告诉你:
try.cpp: In lambda function:
try.cpp:14:9: error: ‘z’ is not captured
a=x+z;
^
try.cpp:12:20: note: the lambda has no capture-default
auto f = [&a,&b,x,y](int n)
^
try.cpp:11:23: note: ‘int z’ declared here
int a=0,b=0,x=10,y=20,z=1;
②[=]//给了苹果不能吃
所有在周围的代码声明的局部变量都可以访问,但只能按值访问(给了苹果但没吃,也就是值没有改变),lambda函数可以访问但是不能修改.
③[参数]//给了苹果,吃不吃随你
该语法中参数是变量的列表,其中每个参数都可以具有或不具有一个符号(&)前缀,说明它是按引用访问的(也就是可以吃(能改变变量值))
.在参数中列出的无&的变量是按值访问它们的:lambda函数可以引用它们,但不会改变它们的值(不能吃,只能闻闻).
#include<iostream>
#include<algorithm>
using std::cout;
using std::endl;
using std::for_each;
int main()
{
int a=0,b=0,x=10,y=20;
auto f = [&a,&b,x,y](int n)
{
a=x;
b=y+n;
};
f(100);
cout<<"a is now"<<a<<endl;
cout<<"b is now"<<b<<endl;
return 0;
}
变量a,b都是按引用访问的,而x和y是按值访问的,因此可以访问a和b能改变其值 ,但x和y不可以改变其值
④[=,参数]
在封闭范围内的所有变量都按值被捕获,任何具有指定的访问模式的参数除外.
例如,下面的闭包指定在封闭范围内的所有范变量都按值访问(不能改变值),但在下面的sum除外
int sum=0;
int n=7;
auto f=[=,&sum](){sum+=n;};
f();//sum=7;(sum数值能改变)
就暂时总结这么多吧