lambda表达式

一、lambda表达式

1.1 lambda表达式的语法

[capture-list] (parameters) mutable -> return-type { statement};

  • [capture-list] : 捕捉列表,该列表总是出现在lambda函数的开始位置,编译器根据[]来判断接下来的代码是否为lambda函数,捕捉列表能够捕捉上下文中的变量供lambda函数使用。

  • (parameters):参数列表。与普通函数的参数列表一致,如果不需要参数传递,则可以连同()一起省略

  • mutable:默认情况下,lambda函数总是一个const函数mutable可以取消其常量性。使用该修饰符时,参数列表不可省略(即使参数为空)

  • ->returntype:返回值类型。用追踪返回类型形式声明函数的返回值类型,没有返回值时此部分可省略。返回值类型明确情况下,也可省略,由编译器对返回类型进行推导

  • {statement}:函数体。在该函数体内,除了可以使用其参数外,还可以使用所有捕获到的变量。

注意:
在lambda函数定义中,参数列表和返回值类型都是可选部分,而捕捉列表和函数体可以为空。因此C++11中最简单的lambda函数为:[]{}; 该lambda函数不能做任何事情。

#include<iostream>
using namespace std;

int main()
{
  	int x = 10, y = 20;
    auto Add1 = [](int a, int b)->int{return a + b;};//没有省略任何一个部分(mutable除外)
    auto Add2 = [](int a, int b){return a + b;};//在返回值类型明确下省略返回值类型
    auto Add3 = [x,y]{return x + y;};//使用捕获列表捕获上下文变量(按值捕获const类型),不使用函数参数列表,返回值类型明确。

    cout << Add1(x, y) << endl;
    cout << Add2(x, y) << endl;
    cout << Add3() << endl;
    return 0;
}

上述代码执行结果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6Neb9osP-1665551058790)(C:\Users\13916\AppData\Roaming\Typora\typora-user-images\image-20221012103500533.png)]

注意:在省略掉(parameters)的时候,->return-type也得省略,否则编译会报错

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CAd1bElZ-1665551058791)(C:\Users\13916\AppData\Roaming\Typora\typora-user-images\image-20221012104114146.png)]

二、lambda表达式各部分说明

2.1 捕捉列表和参数列表说明

捕捉列表描述了上下文中那些数据可以被lambda使用,以及使用的方式传值还是传引用

  • [var]:表示值传递方式捕捉变量var
  • [=]:表示值传递方式捕获所有父作用域中的变量(包括this)
  • [&var]:表示引用传递捕捉变量var
  • [&]:表示引用传递捕捉所有父作用域中的变量(包括this)
  • [this]:表示值传递方式捕捉当前的this指针
#include<iostream>
using namespace std;

int main()
{
    int x = 10, y = 20;
    auto Swap1 = [](int x, int y){int temp = x; x = y; y = temp;};
    auto Swap2 = [](int &x, int &y){int temp = x; x = y; y = temp;};
    int a = 30, b = 40;
    auto Swap3 = [a, b]()mutable{int temp = a; a = b; b = temp;};
    auto Swap4 = [&a, &b]{int temp = a; a = b; b = temp;};

    Swap1(x, y);
    cout << "Swap1:: " << x << " " << y << endl;
    Swap2(x, y);
    cout << "Swap2:: " << x << " " << y << endl;
    Swap3();
    cout << "Swap3:: " << a << " " << b << endl;
    Swap4();
    cout << "Swap4:: " << a << " " << b << endl;

    return 0;
}

上面代码得运行结果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-twg1myz8-1665551058791)(C:\Users\13916\AppData\Roaming\Typora\typora-user-images\image-20221012111317034.png)]

我们发现Swap1和Swap3并没有发生交换,具体分析一下原因:

int x = 10, y = 20;
auto Swap1 = [](int x, int y){int temp = x; x = y; y = temp;};
auto Swap2 = [](int &x, int &y){int temp = x; x = y; y = temp;};

Swap1和Swap2都使用函数参数列表,但是不同的是,Swap1是传值,Swap2是传引用传值传递给形参的是一种拷贝,形参的改变并不会影响实参。传引用传递给形参的是实参的别名,因为是别名,所以对形参的改变也会影响实参。

int a = 30, b = 40;
auto Swap3 = [a, b]()mutable{int temp = a; a = b; b = temp;};
auto Swap4 = [&a, &b]{int temp = a; a = b; b = temp;};

Swap3和Swap4都是使用捕捉列表,但不同的是Swap3是按值捕捉,而Swap4是按引用捕捉按值捕捉也是捕捉上下文变量的拷贝,只不过是const属性的,所以这里就可以用到mutable移除const属性,但是即使是移除了,他还是拷贝,它的改变并不会影响原来变量的值。按引用捕捉就是捕捉上下文变量的别名,它的改变会改变上下文变量的值。

2.2 参数列表、mutable和->return-type之间配合使用的关系

(parameters) 和 -> return-type:

在省略参数列表的时候,->return-type也得省略,不然会编译报错。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wwtcYbFc-1665551058792)(C:\Users\13916\AppData\Roaming\Typora\typora-user-images\image-20221012122746283.png)]

(parameters) 和 mutable:

在省略参数列表的时候,mutable也得省略,不然会编译报错。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IjLUq3qh-1665551058793)(C:\Users\13916\AppData\Roaming\Typora\typora-user-images\image-20221012123116615.png)]

2.3 仿函数与lambda表达式

struct Rate
{
    Rate(double rate): _rate(rate)
    {}
    double operator()(double money, int year)
    { return money * _rate * year;}
private:
	double _rate;
};
int main()
{
    // 函数对象
    double rate = 0.49;
    Rate r1(rate);
    r1(10000, 2);
    // lamber
    auto r2 = [=](double money, int year)->double{return money *rate *year;};
	r2(10000, 2);
    
    return 0;
}

从使用方式上来看,函数对象与lambda表达式完全一样。
函数对象将rate作为其成员变量,在定义对象时给出初始值即可,lambda表达式通过捕获列表可
以直接将该变量捕获到。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NSjjgBMx-1665551058793)(C:\Users\13916\AppData\Roaming\Typora\typora-user-images\image-20221012125037984.png)]

实际在底层编译器对于lambda表达式的处理方式,完全就是按照仿函数的方式处理的,即:如果定义了一个lambda表达式,编译器会自动生成一个类,在该类中重载了operator()。

三、捕捉列表的灵活使用

3.1 [=]与[&]

  • [=]:表示值传递方式捕获所有父作用域中的变量(包括this)

  • [&]:表示引用传递捕捉所有父作用域中的变量(包括this)

#include<iostream>
using namespace std;

int main()
{
	int a = 1, b = 2, c = 3, d = 4, ret = 0;
    auto Add = [=, &ret]{ret = a + b + c + d;};
    Add();
    cout << ret << endl;
	
    return 0;
}

如果上下文需要获取许多变量,并不需要一个一个的捕捉,只需要学会使用[=]和[&]即可, 例如上面的[=, &ret],他就是用值捕捉所有上下文变量,用引用捕捉ret,值捕捉引用捕捉是可以混着一起用的,只需要用逗号隔开就好,例如[=, &d, &ret],还是比较灵活的。

  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

桑榆非晚ᴷ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值