【C++11】来感受lambda表达式的魅力~

在这里插入图片描述

👦个人主页:@Weraphael
✍🏻作者简介:目前学习C++和算法
✈️专栏:C++航路
🐋 希望大家多多支持,咱一起进步!😁
如果文章对你有帮助的话
欢迎 评论💬 点赞👍🏻 收藏 📂 加关注✨


目录

  • 一、仿函数的使用
  • 二、lambda表达式的语法
  • 三、lambda表达式中捕捉列表的玩法
  • 四、lambda表达式的底层原理
  • 五、总结

一、仿函数的使用

假设需要对vector容器里的数据进行排序,那么可以通过算法库的 sort 函数进行排序,至于结果为升序还是降序,可以通过 仿函数( 类+operator()重载) 控制。

struct Great // > - 降序
{bool operator()(int x, int y){return x > y;}
};struct Less // < - 升序
{bool operator()(int x, int y){return x < y;}
};int main()
{vector<int> v{1, 3, 5, 9, 7, 0, 4, 2, 6, 8};// Less() - 仿函数的匿名对象sort(v.begin(), v.end(), Less()); // 升序cout << "升序:";for (auto e : v){cout << e << " ";}cout << endl;// Great() - 仿函数的匿名对象sort(v.begin(), v.end(), Great()); // 降序cout << "降序:";for (auto e : v){cout << e << " ";}cout << endl;return 0;
}

【程序结果】

在这里插入图片描述

这看起来仿函数用起来也非常的香啊~。但如果某些程序员非常不注重代码风格,是这样写代码的:

struct func1 // > - 降序
{bool operator()(int x, int y){return x > y;}
};struct func2 // < - 升序
{bool operator()(int x, int y){return x < y;}
};sort(v.begin(), v.end(), func1()); 
sort(v.begin(), v.end(), func2()); 

这样写是不是非常的恶心,这样命名风格就算了,旁边还不给个注释,这不是欠揍嘛hh;而且万一仿函数在别的文件里,那么我们还要去找。

因此C++11支持了一个新语法:lambda 表达式。它可以快速构建局部的匿名函数对象,作为函数中的参数

接下来大家先见见猪跑,至于怎么使用lambda 表达式,后面会介绍

int main()
{vector<int> v{1, 3, 5, 9, 7, 0, 4, 2, 6, 8};sort(v.begin(), v.end(), [](int x, int y)->bool {return x < y; }); // 升序cout << "升序:";for (auto e : v){cout << e << " ";}cout << endl;// Great() - 仿函数的匿名对象sort(v.begin(), v.end(), [](int x, int y)->bool {return x > y; }); // 降序cout << "降序:";for (auto e : v){cout << e << " ";}cout << endl;return 0;
}

【程序结果】

在这里插入图片描述

由此可见,lambda表达式相对于传统的仿函数来说,更加灵活和简洁

二、lambda表达式的语法

书写格式:[ ]( ) mutable ->returntype { }

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

  • ( ) 参数列表。与普通函数的参数列表一个意思。如果没有参数,那么可以连通()一起省略。

  • mutable 关键字mutable可以取消捕捉列表中参数的常量属性。注意:使用该修饰符时,即使参数为空,参数列表的()不可省略。(但是基本不常用)

  • ->returntype 返回值类型。这里的返回值类型几乎可以不用写。

  • { } 函数体。和普通函数一样,当然支持多语句。但是不能函数体内不能使用局部的变量及函数,如果想使用,需要配合捕捉列表

这里再次声明:

  • lambda 表达式 构建出的是一个 局部的匿名函数对象,匿名函数对象也可以调用,不过要在创建后立马调用,因为匿名对象生命周期只有一行

  • 如果需要显式调用,可以使用 auto 推导 匿名函数对象 的类型,然后将创建出来的 匿名函数对象 赋给一个 有名函数对象

在这里插入图片描述

三、lambda表达式中捕捉列表的玩法

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

    • [val]:表示值传递捕捉变量val
    • [&val]:表示引用传递捕捉变量val(修改变量)

    比如,使用lambda表达式交换局部变量ab

    在这里插入图片描述

    这是因为 捕捉列表 中的参数是一个传值捕捉,而捕捉列表 中的参数默认具有 常量属性,不能直接修改,但可以添加 mutable 关键字 取消常性
    在这里插入图片描述

    但输出结果发现两个值并没有修改。这里其实就类似于普通函数的值传递,局部变量的ab只是拷贝给捕捉列表参数,并没有建立联系,因此,这里的捕捉列表需要用引用传递的方式
    在这里插入图片描述

    • [&]表示引用传递捕捉所有在当前作用域中的所有变量

    需要注意的是:lambda函数体内不允许使用当前作用域中的变量,除非在捕捉列表声明,否则会报错。

    在这里插入图片描述

    这里有两个方法,要么在捕捉列表捕捉,要么将捕捉列表写成[&]表示引用传递捕捉所有在当前作用域中的所有变量

    在这里插入图片描述

    • [=]表示值传递捕捉所有在当前作用域中的所有变量。

    在这里插入图片描述

    注意:

    • 捕捉列表 的使用非常灵活,比如 [&, x] 表示只有x 使用 传值捕捉,其他变量使用 引用捕捉[=, &str] 表示 str 使用 引用捕捉,其他变量使用 传值捕捉

    • 捕捉列表不允许变量重复传递,否则就会导致编译错误。比如:[=, a]:捕捉a重复。

    • lambda表达式之间不能相互赋值。因为它们之间的类型是不一样的!至于为什么呢?后面讲底层就知道了~

    在这里插入图片描述

四、lambda表达式的底层原理

其实lambda表达式用起来非常香,这是因为它的底层是仿函数;就像范围for一样,看似是简短的几行代码,底层确实一个迭代器。

我们可以使用以下代码样例,通过查看反汇编:

struct func
{void operator()(int x, int y){cout << "operator()(int x, int y)" << endl;}
};int main()
{int a = 3;int b = 3;// 仿函数对象实例化func f;f(a, b);// lambda表达式auto e = [=](int x, int y) {cout << "[=](int x, int y)" << endl;};e(a, b);return 0;
a, b);return 0;
}

【反汇编】

在这里插入图片描述

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

并且这个类被命名为:lambda_uuid

uuid通用唯一标识码,可以生成一个重复率极低的辨识信息,避免类名冲突,这也意味着即便是两个功能完全一样的 lambda 表达式,也无法进行赋值,因为 lambda_uuid 肯定不一样

所以在编译器看来,lambda 表达式 本质上就是一个 仿函数

五、总结

当涉及到C++lambda表达式时,可以得出以下总结:

  1. 匿名函数: lambda表达式允许在需要函数对象的地方快速定义匿名函数,无需显式命名,可直接内联使用。

  2. 捕获外部变量: lambda表达式能够捕获其作用域内的变量,可以按值或按引用捕获,使得在算法和回调函数中处理外部变量更加方便。

  3. 简洁性: lambda表达式使代码更加紧凑和简洁,尤其在需要传递简单的函数对象时,可以省去冗余的代码。

  4. 可读性: 使用lambda表达式可以将算法和行为直接嵌入到使用它们的地方,使代码更具可读性和易于理解。

  5. 函数式编程: 引入lambda表达式后,C++增强了函数式编程的能力,使得处理一些函数式编程的场景更加便利。

需要注意的是,lambda表达式并不是完全取代传统的仿函数,而是在某些情况下更加方便和实用。例如,在需要长期复用、需要命名或需要在多个地方多次使用的情况下,传统的仿函数仍然有其价值。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/740915.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

redis题库详解

1 什么是Redis Redis(Remote Dictionary Server) 是一个使用 C 语言编写的&#xff0c;开源的&#xff08;BSD许可&#xff09;高性能非关系型&#xff08;NoSQL&#xff09;的键值对数据库。 Redis 可以存储键和五种不同类型的值之间的映射。键的类型只能为字符串&#xff0c;…

《OWASP TOP10漏洞》

0x01 弱口令 产生原因 与个人习惯和安全意识相关&#xff0c;为了避免忘记密码&#xff0c;使用一个非常容易记住 的密码&#xff0c;或者是直接采用系统的默认密码等。 危害 通过弱口令&#xff0c;攻击者可以进入后台修改资料&#xff0c;进入金融系统盗取钱财&#xff0…

ENVI 如何批量拆分多波段栅格

在处理遥感图像时&#xff0c;需要将多波段栅格进行拆分是很常见的需求。下面介绍一种方法&#xff0c;可以实现图像批量拆分并重命名。 打开ENVI的App Store 搜索并下载应用 在ENVI的App Store中搜索"将多波段图像拆分成多个单波段文件"&#xff0c;并下载安装。 打…

OceanBase4.2版本 Docker 体验

&#x1f4e2;&#x1f4e2;&#x1f4e2;&#x1f4e3;&#x1f4e3;&#x1f4e3; 哈喽&#xff01;大家好&#xff0c;我是【IT邦德】&#xff0c;江湖人称jeames007&#xff0c;10余年DBA及大数据工作经验 一位上进心十足的【大数据领域博主】&#xff01;&#x1f61c;&am…

当电脑加域控后,自动移入指定的OU

在Active Directory&#xff08;AD&#xff09;环境中&#xff0c;要实现当计算机加入域时自动被放置到指定的OU&#xff08;组织单元&#xff09;&#xff0c;通常需要配置组策略对象&#xff08;GPO&#xff09;中的计算机账户默认位置或者使用redircmp命令来重定向新加入域的…

视频AI方案:数据+算力+算法,人工智能的三大基石

背景分析 随着信息技术的迅猛发展&#xff0c;人工智能&#xff08;AI&#xff09;已经逐渐渗透到我们生活的各个领域&#xff0c;从智能家居到自动驾驶&#xff0c;从医疗诊断到金融风控&#xff0c;AI的应用正在改变着我们的生活方式。而数据、算法和算力&#xff0c;正是构…

2024 年 2 月 NFT 行业动态:加密货币飙升,NFT 市场调整

作者&#xff1a;stellafootprint.network 数据来源&#xff1a;NFT 研究页面 - Footprint Analytics 2024 年 2 月&#xff0c;加密货币与 NFT 市场显现出了复杂性。该月&#xff0c;NFT 领域的交易量达到 12 亿美元&#xff0c;环比下降了 3.7%。值得关注的是&#xff0c;包…

【IC验证】数组

一、非组合型数组 1.声明 logic [31:0] array [1024]; 或者logic [31:0] array [1023:0]; 或者logic array [31:0] [1023:0]; 理解成一维数组就表示array 数组中有1024个数据&#xff0c;每个数据32bit。 也可以理解为二维数组。 int [1:0][2:0]a1[3:0][4:0]这是一个4523维…

springboot267大学生科创项目在线管理系统的设计与实现

# 大学生科创项目在线管理系统设计与实现 摘 要 传统办法管理信息首先需要花费的时间比较多&#xff0c;其次数据出错率比较高&#xff0c;而且对错误的数据进行更改也比较困难&#xff0c;最后&#xff0c;检索数据费事费力。因此&#xff0c;在计算机上安装大学生科创项目在…

【论文阅读】ACM MM 2023 PatchBackdoor:不修改模型的深度神经网络后门攻击

文章目录 一.论文信息二.论文内容1.摘要2.引言3.作者贡献4.主要图表5.结论 一.论文信息 论文题目&#xff1a; PatchBackdoor: Backdoor Attack against Deep Neural Networks without Model Modification&#xff08;PatchBackdoor:不修改模型的深度神经网络后门攻击&#xf…

数据结构从入门到精通——树和二叉树

树和二叉树 前言一、树概念及结构1.1树的概念1.2 树的相关概念&#xff08;重要&#xff09;1.3 树的表示1.4 树在实际中的运用&#xff08;表示文件系统的目录树结构&#xff09; 二、二叉树概念及结构2.1二叉树概念2.2现实中的二叉树2.3 特殊的二叉树2.4 二叉树的性质2.5 二叉…

基于Java+SpringBoot+vue+element疫情药品采购出入库系统设计实现

基于JavaSpringBootvueelement疫情药品采购出入库系统设计实现 博主介绍&#xff1a;多年java开发经验&#xff0c;专注Java开发、定制、远程、文档编写指导等,csdn特邀作者、专注于Java技术领域 作者主页 央顺技术团队 Java毕设项目精品实战案例《1000套》 欢迎点赞 收藏 ⭐留…

(2)(2.12) Robsense SwarmLink

文章目录 前言 1 规格&#xff08;根据制造商提供&#xff09; 2 EasySwarm 3 参数说明 前言 Robsense SwarmLink 遥测无线电可将多架无人机连接到一个地面站&#xff0c;而无需在地面站一侧安装多个无线电&#xff08;即创建一个网状网络&#xff09;。此外&#xff0c;还…

在项目管理中,如何更好地协同团队成员,提高团队合作效率?

在项目管理中&#xff0c;协同团队成员并提高团队合作效率是确保项目成功实施的关键。以下是一些建议&#xff0c;有助于更好地协同团队成员&#xff0c;提高团队合作效率&#xff1a; 一、明确角色与责任 为每个团队成员分配明确的角色和职责&#xff0c;通过制定详细的任务…

用chatgpt写论文重复率高吗?如何降低重复率?

ChatGPT写的论文重复率很低 ChatGPT写作是基于已有的语料库和文献进行训练的&#xff0c;因此在写作过程中会不可避免地引用或借鉴已有的研究成果和观点。同时&#xff0c;由于ChatGPT的表述方式和写作风格与人类存在一定的差异&#xff0c;也可能会导致论文与其他文章相似度高…

程序人生——Java中基本类型使用建议

目录 引出Java中基本类型使用建议建议21&#xff1a;用偶判断&#xff0c;不用奇判断建议22&#xff1a;用整数类型处理货币建议23&#xff1a;不要让类型默默转换建议24&#xff1a;边界、边界、还是边界建议25&#xff1a;不要让四舍五入亏了一方 建议26&#xff1a;提防包装…

掘根宝典之C++迭代器简介

在C中&#xff0c;容器是一种用于存储和管理数据的数据结构。C标准库提供了多种容器&#xff0c;每种容器都有其独特的特点和适用场景。 我们知道啊&#xff0c;我们可以通过下标运算符来对容器内的元素进行访问&#xff0c;但是只有少数几种容器才同时支持下标运算符&#xf…

闲聊电脑(7)常见故障排查

闲聊电脑&#xff08;7&#xff09;常见故障排查 夜深人静&#xff0c;万籁俱寂&#xff0c;老郭趴在电脑桌上打盹&#xff0c;桌子上的小黄鸭和桌子旁的冰箱又开始窃窃私语…… 小黄鸭&#xff1a;冰箱大哥&#xff0c;平时遇到电脑故障该咋处理呢&#xff1f; 冰箱&#xf…

k8s中calico网络组件部署时一个节点一直处于Pending状态

k8s中calico网络组件部署时一个节点一直处于Pending状态 故障截图 故障排查思路&#xff0c;通过describe查看具体原因 ~]# kubectl describe pod calico-node-pzlfv -n kube-system通过describe查看得知报错 Warning FailedScheduling 58s (x23 over 23m) default-sche…

基于YOLOv8/YOLOv7/YOLOv6/YOLOv5的扑克牌识别软件(Python+PySide6界面+训练代码)

摘要&#xff1a;开发扑克牌识别软件对于智能辅助决策工具的建立具有关键作用。本篇博客详细介绍了如何运用深度学习构建一个扑克牌识别软件&#xff0c;并提供了完整的实现代码。该系统基于强大的YOLOv8算法&#xff0c;并对比了YOLOv7、YOLOv6、YOLOv5&#xff0c;展示了不同…