学习lambda

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数值能改变)


就暂时总结这么多吧

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值