0%

C++之lambda表达式

C++11之后引入lambda表达式,,一般用于定义匿名函数,使得代码更加灵活简洁。lambda表达式与普通函数类似,也有参数列表、返回值类型和函数体,只是它的定义方式更简洁,并且可以在函数内部定义。

1 lambda表达式概述

最常见的lambda表达式如下:

1
2
auto plus = [] (int v1, int v2) -> int { return v1 + v2; }
int sum = plus(1, 2);

上述代码是计算两数之和的,但是一般不会这样使用

2 lambda表达式的写法

序号 写法
(1) [captures]<tparams>(params)lambda-specifiers{body}
(2) [captures](params)rtailing-return-type{body}
(3) [captures](params){body}
(4) [captures]lambda-specifiers{body}

3 四种表达式的含义

(1)完整的lambda表达式,包含了lambda表达式的所有成分。
(2)常量lambda表达式,捕获的变量都是常量,不能在lambda表达式的body中进行修改。
(3)和(2)基本一致,唯一的区别就是,lambda表达式的函数返回值可以通过函数体推导出来。一般情况函数返回值类型明确或者没有返回值的情况下可以这样写。
(4)lambda表达式的函数没有任何参数,但是可以添加lambda-specifiers,lambda-specifiers是什么我们后续再介绍。

4 lambda表达式各个成员的解释

captures 捕获列表,lambda可以把上下文变量以值或引用的方式捕获,在body中直接使用。

tparams 模板参数列表(c++20引入),让lambda可以像模板函数一样被调用。

params 参数列表,有一点需要注意,在c++14之后允许使用auto左右参数类型。

lambda-specifiers lambda说明符, 一些可选的参数,这里不多介绍了,有兴趣的读者可以去官方文档上看。这里比较常用的参数就是mutable和exception。其中,表达式(1)中没有trailing-return-type,是因为包含在这一项里面的。

trailing-return-type 返回值类型,一般可以省略掉,由编译器来推导。

body 函数体,函数的具体逻辑。

5 捕获列表

上面介绍完了lambda表达式的各个成分,其实很多部分和正常的函数没什么区别,其中最大的一个不同点就是捕获列表。我在刚开始用lambda表达式的时候,还一直以为这个没啥用,只是用一个 [] 来标志着这是一个lambda表达式。后来了解了才知道,原来这个捕获列表如此强大,甚至我觉得捕获列表就是lambda表达式的灵魂。下面先介绍几种常用的捕获方式。

[] 什么也不捕获,无法lambda函数体使用任何

[=] 按值的方式捕获所有变量

[&] 按引用的方式捕获所有变量

[=, &a] 除了变量a之外,按值的方式捕获所有局部变量,变量a使用引用的方式来捕获。这里可以按引用捕获多个,例如 [=, &a, &b,&c]。这里注意,如果前面加了=,后面加的具体的参数必须以引用的方式来捕获,否则会报错。

[&, a] 除了变量a之外,按引用的方式捕获所有局部变量,变量a使用值的方式来捕获。这里后面的参数也可以多个,例如 [&, a, b, c]。这里注意,如果前面加了&,后面加的具体的参数必须以值的方式来捕获。

[a, &b] 以值的方式捕获a,引用的方式捕获b,也可以捕获多个。

[this] 在成员函数中,也可以直接捕获this指针,其实在成员函数中,[=]和[&]也会捕获this指针。

6 总结

  • 捕获列表,对应LambdaClass类的private成员。

  • 参数列表,对应LambdaClass类的成员函数的operator()的形参列表

  • mutable,对应 LambdaClass类成员函数 operator() 的const属性 ,但是只有在捕获列表捕获的参数不含有引用捕获的情况下才会生效,因为捕获列表只要包含引用捕获,那operator()函数就一定是非const函数。

  • 返回类型,对应 LambdaClass类成员函数 operator() 的返回类型

  • 函数体,对应 LambdaClass类成员函数 operator() 的函数体。

  • 引用捕获和值捕获不同的一点就是,对应的成员是否为引用类型。

感谢看到这里,在记录中收获成长,道阻且长