电子工程师技术服务社区
公告
登录
|
注册
首页
技术问答
厂商活动
正点原子
板卡试用
资源库
下载
文章
社区首页
文章
C++的匿名函数(lambda表达式)
分 享
扫描二维码分享
C++的匿名函数(lambda表达式)
C++
良知犹存
关注
发布时间: 2020-10-09
丨
阅读: 288
> 总述 > > C++11提供了对匿名函数的支持,称为Lambda函数(也叫Lambda表达式). 它是定义和使用匿名函数对象的一种简便的方式。匿名函数是我们需要用到的一个函数,但是又不想去费力命名一个函数的场景。我们无需为每个值或者每种类型)单独编写函数,更不必把值保存在让人厌倦的全局变量中 。 利用lambda表达式可以编写内嵌的匿名函数,用以替换独立函数或者函数对象,并且使代码更可读。 > > 工作的时候这个是比较常用的,通过匿名函数进行函数内部变量的捕获,继而进行操作变量等。那么现在就由我来给大家分享一下,我对Lambda表达式的认知,仅作为一个基础的介绍哈,毕竟C++博大精深,吾辈还需要深究。 作者:良知犹存 转载授权以及围观:欢迎添加微信公众号:Conscience_Remains # 1 **它的结构** # 一条lambda表达式一般会有以下部分: 1.一个可能为空的捕获列表,指明定义环境中的那些名字能被用在lambda表达式内,以及这些名字的访问形式拷贝还是引用,捕获列表位于 [] 内。 2.一个可选的参数列表,指明lambda表达式所需的参数,参数列表位于 () 内。 3.一个可以选的mutable修饰符,指明该lambda表达式可能会修改它自身的状态(即,改变通过值捕获的变量的副本) 4.一个可选的 -> 形式的返回类型声明 5.一个表达式体,指明要执行的代码,表达式位于 {} 内。 ``` [捕获列表](参数列表) mutable(可选) 异常属性 -> 返回类型 { // 函数体 } ``` ![Click and drag to move](data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==) 上面的语法规则除了 `[捕获列表]` 内的东西外,其他部分都很好理解,只是一般函数的函数名被略去, 返回值使用了一个 `->` 的形式进行。 所谓捕获列表,其实可以理解为参数的一种类型,lambda 表达式内部函数体在默认情况下是不能够使用函数体外部的变量的, 这时候捕获列表可以起到传递外部数据的作用。 在lambda中,传参、返回结果以及定义表达式体和普通的函数都是一致的,区别就在于普通函数没有提供局部变量“捕获”功能,而局部捕获的功能,就意味着lambda可以做局部函数使用,而普通函数不能。 **展示一个小例子证明lambda表达式的简洁性**: Greater than 是一个函数对象,保存了要比较的值: ``` struct Greater_than { int val; Greater_than(lnt v) : val{v} { }; bool operatorO(const pair
& r) { return r.second>val;}}; ``` 我们也可以使用 lambda 表达式 : ``` auto p =find_if(m.beginO, m.endO, [](const pair
& r) { return r.second>42; }); ``` 每当你定义一个`lambda`表达式后,编译器会自动生成一个匿名类(这个类当然重载了`()`运算符),我们称为闭包类型(closure type)。 # 2 **基本的参数分析** # C++11中的Lambda表达式捕获外部变量主要有以下形式: - []:默认不捕获任何变量; - [=]:默认以值捕获所有变量; - [&]:默认以引用捕获所有变量; - [x]:仅以值捕获x,其它变量不捕获; - [&x]:仅以引用捕获x,其它变量不捕获; - [=, &x]:默认以值捕获所有变量,但是x是例外,通过引用捕获; - [&, x]:默认以引用捕获所有变量,但是x是例外,通过值捕获; - [this]:通过引用捕获当前对象(其实是复制指针); - [*this]:通过传值方式捕获当前对象; 在上面的捕获方式中,注意最好不要使用[=]和[&]默认捕获所有变量。首先说默认引用捕获所有变量,你有很大可能会出现悬挂引用(Dangling references),因为引用捕获不会延长引用的变量的声明周期,例如一个形参传进来我们进行捕获并作为一个返回值执行。**因为函数传参进来之后,本函数不会保存该变量,函数执行完就会自动释放,那么这个时候返回值就可能产生一个没有意义的结果。** ``` auto evt_set_status_x = [&](EventType x){ status[x] = true;/@@*通过引用捕获的变量 我们可以进行修改变量的数据*/}; ``` [&]是一个捕获列表( capture l ist ), 它指明所用的局部名字(如 x) 将通过引用访问 。如果我们希望只"捕获 "x ,则可以写成 [&x] ;如果希望给生成的函数对象传递一个 的拷贝, 则写成[ x] 。什么也不捕获是[],捕获所有通过引用访问的局部名字是[&],捕获所有以值访问的局部名字是[=] 。 并且lambda表达式也可以赋值给相对应的函数指针,这也使得你完全可以把lambda表达式看成对应函数类型的指针。 当我们需要访问它的局部变量的时候,**我们需要特别定义捕获列表中的类型** 下面是一个**没有使用**局部变量的lambda表达式,所以它的[]里面为空 ``` void part(vector
& v){ sort(v.begin,v.end);//排列值 sort(v.begin,v.end, [](int x,int y){return abs(x) < abs(y);});//排列绝对值 } ``` 下面是一个**使用**局部变量的lambda表达式,所以它的[]里面**为空就会出错** ``` void part(vector
& v){ bool value = true; sort(v.begin,v.end, [](int x,int y){return value ? x
void value_capture() { int value = 1; auto copy_value = [value] { return value; }; value = 100; auto stored_value = copy_value(); std::cout << "stored_value=" << stored_value << std::endl;} int main(int argc,char ** argv){ value_capture();}// 这时, stored_value == 1, 而 value == 100.// 因为 copy_value 在创建时就保存了一份 value 的拷贝 ``` ![img](https://img-blog.csdnimg.cn/img_convert/58fb01ff17e1c9aee47f3b1a5c07d784.png)![Click and drag to move](data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==) 记得编译的时候加 -std=c++11 ## **引用捕获** ## 与引用传参类似,引用捕获保存的是引用,值会发生变化: ``` void reference_capture() { int value = 1; auto copy_value = [&value] { return value; }; value = 100; auto stored_value = copy_value(); std::cout << "stored_value=" << stored_value << std::endl; // 这时, stored_value == 100, value == 100. // 因为 copy_value 保存的是引用 } ``` ![Click and drag to move](data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==) ![img](https://img-blog.csdnimg.cn/img_convert/94d0cbc620a6fe38c05834cfc433ed93.png)![Click and drag to move](data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==) ## 泛型lambda表达式 从`C++14`开始,`lambda`表达式支持泛型:其参数可以使用自动推断类型的功能,而不需要显示地声明具体类型。这就如同函数模板一样,参数要使用类型自动推断功能,只需要将其类型指定为`auto`,类型推断规则与函数模板一样。就用我最早给出的那个例子好了。 ``` auto evt_set_status_x = [&](EventType x){ status[x] = true;}; ``` 这就是我分享的c++中的lambda表达式,以后有机会再往深入去分析一哈,其次如果大家有什么更好的思路,欢迎分享交流哈。
原创作品,未经权利人授权禁止转载。详情见
转载须知
。
举报文章
点赞
(
0
)
良知犹存
关注
评论
(0)
登录后可评论,请
登录
或
注册
相关文章推荐
MK-米客方德推出工业级存储卡
Beetle ESP32 C3 蓝牙数据收发
Beetle ESP32 C3 wifi联网获取实时天气信息
开箱测评Beetle ESP32-C3 (RISC-V芯片)模块
正点原子数控电源DP100测评
DP100试用评测-----开箱+初体验
Beetle ESP32 C3环境搭建
【花雕体验】16 使用Beetle ESP32 C3控制8X32位WS2812硬屏之二
X
你的打赏是对原创作者最大的认可
请选择打赏IC币的数量,一经提交无法退回 !
100IC币
500IC币
1000IC币
自定义
IC币
确定
X
提交成功 ! 谢谢您的支持
返回
我要举报该内容理由
×
广告及垃圾信息
抄袭或未经授权
其它举报理由
请输入您举报的理由(50字以内)
取消
提交