您现在的位置是:亿华云 > 应用开发
C++的匿名函数(lambda表达式)
亿华云2025-10-08 22:59:59【应用开发】7人已围观
简介总述C++11提供了对匿名函数的支持,称为Lambda函数(也叫Lambda表达式). 它是定义和使用匿名函数对象的一种简便的方式。匿名函数是我们需要用到的一个函数,但是又不想去费力命名一个函数的场景
总述
C++11提供了对匿名函数的匿名支持,称为Lambda函数(也叫Lambda表达式). 它是定义和使用匿名函数对象的一种简便的方式。匿名函数是函数我们需要用到的一个函数,但是表达又不想去费力命名一个函数的场景。我们无需为每个值或者每种类型)单独编写函数,匿名更不必把值保存在让人厌倦的函数全局变量中 。 利用lambda表达式可以编写内嵌的表达匿名函数,用以替换独立函数或者函数对象,匿名并且使代码更可读。函数
工作的表达时候这个是比较常用的,通过匿名函数进行函数内部变量的匿名捕获,继而进行操作变量等。函数那么现在就由我来给大家分享一下,表达我对Lambda表达式的匿名认知,仅作为一个基础的函数介绍哈,毕竟C++博大精深,表达吾辈还需要深究。
1.它的结构
一条lambda表达式一般会有以下部分:
1.一个可能为空的云南idc服务商捕获列表,指明定义环境中的那些名字能被用在lambda表达式内,以及这些名字的访问形式拷贝还是引用,捕获列表位于 [] 内。
2.一个可选的参数列表,指明lambda表达式所需的参数,参数列表位于 () 内。
3.一个可以选的mutable修饰符,指明该lambda表达式可能会修改它自身的状态(即,改变通过值捕获的变量的副本)
4.一个可选的 -> 形式的返回类型声明
5.一个表达式体,指明要执行的代码,表达式位于 { } 内。
[捕获列表](参数列表) mutable(可选) 异常属性 -> 返回类型 { // 函数体 }上面的语法规则除了 [捕获列表] 内的东西外,其他部分都很好理解,只是一般函数的函数名被略去, 返回值使用了一个 -> 的形式进行。免费信息发布网
所谓捕获列表,其实可以理解为参数的一种类型,lambda 表达式内部函数体在默认情况下是不能够使用函数体外部的变量的, 这时候捕获列表可以起到传递外部数据的作用。
在lambda中,传参、返回结果以及定义表达式体和普通的函数都是一致的,区别就在于普通函数没有提供局部变量“捕获”功能,而局部捕获的功能,就意味着lambda可以做局部函数使用,而普通函数不能。
展示一个小例子证明lambda表达式的简洁性:
Greater than 是一个函数对象,保存了要比较的值:
struct Greater_than ( int val; Greater_than(lnt v) : val{ v} { } bool operatorO(const pair<string.int>& r) { return r.second>val; };我们也可以使用 lambda 表达式 :
auto p =find_if(m.beginO, m.endO, [](const pair<string, int>& 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<int>& v) { sort(v.begin,v.end);//排列值 sort(v.begin,v.end, [](int x,int y){ return abs(x) < abs(y);});//排列绝对值 }下面是一个使用局部变量的lambda表达式,所以它的[]里面为空就会出错
void part(vector<int>& v) { bool value = true; sort(v.begin,v.end, [](int x,int y){ return value ? x<y:abs(x) < abs(y);});/ }这时候就错误了,因为我们用到了value这个局部变量,而没有进行捕获列表的设置。
3.捕获使用分析
使用 lambda 虽然简单便捷,但也有可能显得晦涩难懂 。
值捕获
与参数传值类似,值捕获的前提是变量可以拷贝,不同之处则在于,被捕获的变量在 lambda 表达式被创建时拷贝, 而非调用时才拷贝:
#include <iostream> 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 的拷贝记得编译的时候加 -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 保存的是引用 }泛型lambda表达式
从C++14开始,lambda表达式支持泛型:其参数可以使用自动推断类型的功能,而不需要显示地声明具体类型。这就如同函数模板一样,参数要使用类型自动推断功能,只需要将其类型指定为auto,类型推断规则与函数模板一样。就用我最早给出的那个例子好了。
auto evt_set_status_x = [&](EventType x) { status[x] = true; };本文转载自微信公众号「羽林君」,可以通过以下二维码关注。转载本文请联系羽林君公众号。
很赞哦!(44949)
相关文章
- 众所周知,com域名拥有最大的流通市场和流通历史。最好选择com域名,特别是在购买域名时处理域名。其次可以是cn域名、net域名、org域名等主流域名,现在比较流行的王域名和顶级域名,都是值得注册和投资的。
- 元宇宙真的是人间天堂吗?元宇宙时代的五大风险
- 这个 Go 语言的经典 “坑”,我算是服了
- 老域名是需要从新注册吗?
- 其次,一般域名注册有一个获取密码的按钮,域名注册商点击后会向您发送密码。在得到域名注册商发送的密码后,将其传输到域名服务提供商网站,然后输入密码,此时域名呈现申请状态。提交申请后,原注册人通常会向您发送一封电子邮件,询问您是否同意转让。此时,您只需点击同意转移按钮,域名注册商就可以成功转移。
- Go 泛型的三个核心设计,你学会了吗?
- 如何买到域名?
- 【架构必备】读写分离的方方面面及主要设计
- 第六:这个圈子里的域名确实是赚钱的一些大玩家,至于小米农,有多少赚钱?几乎没有,也就是说,轿子里只有一个人,而且大多数人都抬着轿子。
- Python 开发神技 -- 使用管道 Pipe