C++ Lambda表达式的常见用法

news/2024/5/14 10:51:24/文章来源:https://blog.csdn.net/qq_37457202/article/details/129672648

⭐️我叫忆_恒心,一名喜欢书写博客的在读研究生👨‍🎓。
如果觉得本文能帮到您,麻烦点个赞👍呗!

近期会不断在专栏里进行更新讲解博客~~~ 有什么问题的小伙伴 欢迎留言提问欧,喜欢的小伙伴给个三连支持一下呗。👍⭐️❤️

在这里插入图片描述

前言

作为C++11的新特性的Lambada表达式本身书写倒不是什么难事,网上找一找也能轻易写出正确地表达式,但是在那些场景下使用以及应该如何使用反而会让很多新手困惑。

Lambda表达式

1 表达式定义

构造一个闭包:一个能够捕获作用域中变量的未命名函数对象。

在操作上,闭包是将函数与环境一起存储的记录。

2 书写规范

主要分成六个部分,其中1,2,3,5,6是需要重点掌握的。

image-20230318102039495

  1. capture 子句(在 C++ 规范中也称为 lambda 引入器。)
  2. 参数列表自选。(也称为 lambda 声明符)
  3. 可变规范自选。
  4. 异常规范自选。
  5. 尾随返回类型自选。
  6. λ体。

3 书写表达式

书写[] 用于捕获:

3.1 捕获的基本规则

  • [] - 不捕捉任何变量
  • [&] - 捕获外部作用域中所有变量,并作为引用在函数体内使用 (按引用捕
    获)
  • [=] - 捕获外部作用域中所有变量(依赖于编译器,只能捕获不被优化的变量),并作为副本在函数体内使用 (按值捕获)
    注:拷贝的副本在匿名函数体内部为const类型.
  • [=, &foo] - 按值捕获外部作用域中所有变量,并按照引用捕获外部变量 foo
  • [bar] - 按值捕获 bar 变量,同时不捕获其他变量
  • [&bar] - 按引用捕获 bar 变量,同时不捕获其他变量
  • [this] - 捕获当前类中的 this 指针
  • 让 lambda 表达式拥有和当前类成员函数同样的访问权限
    如果已经使用了 & 或者 =, 默认添加此选项

3.2 使用的场景

用到函数指针的地方,应该考虑一下这个地方需不需要写Lambada表达式。

类中定义了只使用一次的方法,可以考虑是否需要用到Lambada表达式。

只需要使用一次

类中进行调用。

好处:

  • 简化代码: 维护代码完整性
  • 捕获列表 简化代码解耦。

具体的例子:

01、代码维护上

Lambada类似于函数指针的东西,比如sort函数 自定义排序.

auto compare = [](int a, int b)
{return a > b;
};

02、代码解耦

如果某天多了一个条件,那么普通的函数参数列表要跟着改变,但是可以使用用匿名函数进行解耦。

例子:

int lambadaParams()
{bool cond1 = false;bool cond2 = false;bool cond3 = true;bool cond4 = true;auto fun = [=](int t){if (cond1){cout << "cond1 is true" << endl;cout << t << endl;}if (cond1 && cond2){cout << "cond1 && cond2" << endl;cout << t << endl;}if (cond3 || cond4){cout << "cond3 || cond4" << endl;cout << t << endl;}};if (true){fun(1);}if (true){fun(2);}if (true){fun(3);}
}

3.3 细节——需要对捕获的值进行修改

由于捕获的值在函数内部是const类型,直接修改会报错。

image-20230317224740489

注:拷贝的副本在匿名函数体内部为const类型.

但是可以添加可变规范

    int num1 = 2;int num2 = 3;auto fun3 = [=](int a, int b) mutable{int p = num1 + num2;int q = (num1--) + (num2--);};fun3(1, 2);

3.4 细节——接收返回值时需要注意

image-20230317223958636

使用 auto 类型说明符声明的变量不能出现在其自身的初始值设定项中。

正确修改:

    std::function<int(int)> fun2 = [&fun2](int a){if (a == 1)return 1;if (a == 2)return 2;elsereturn fun2(a - 1) + fun2(a - 2);};auto x2 = fun2(5);

运行:

image-20230317224148679

3.5 细节——不写返回值会报错的情况

虽然一般Lambada可以不写返回值类型。

当编译器无法进行推断出来类型的时候就会报错。

image-20230317222944937

只需要指明类型就科一了

    auto fun1 = []() -> std::initializer_list<int>{return {1, 2, 3, 4, 5};};auto x = fun1();

运行:

image-20230317223322867

还有一种情况需要注意的是当返回值多个类型的时候,根据某个条件进行返回不同的类型这个时候也需要指明返回值类型。

3.6 细节——其他

引用捕获有性能代价么?

需要,这种效率比较细微,体现在

=引用捕获只针对不被编译器优化的部分:

只会捕获使用的变量而不是全部变量,编译器优化问题。不过我用的gcc版本问题对a1进行了初始化,因此fun4依然可以捕获到

例如:

    int a1, b1, c1;auto fun4 = [=](int num1, int num2) mutable{num1++;num2++;num1 = a1 + num1;};fun4(0, 1);

完整的实验代码:

#include <iostream>
#include <algorithm>
#include <vector>
#include <functional>
using namespace std;
int main()
{vector<int> vec{3, 5, 1, 8, 2, 9, 0};auto compare = [](int a, int b){return a > b;};sort(vec.begin(), vec.end(), compare);auto fun1 = []() -> std::initializer_list<int>{return {1, 2, 3, 4, 5};};auto x = fun1();std::function<int(int)> fun2 = [&fun2](int a){if (a == 1)return 1;if (a == 2)return 2;elsereturn fun2(a - 1) + fun2(a - 2);};auto x2 = fun2(5);int num1 = 2;int num2 = 3;auto fun3 = [=](int a, int b) mutable{int p = num1 + num2;int q = (num1--) + (num2--);};fun3(1, 2);int a1, b1, c1;auto fun4 = [=](int num1, int num2) mutable{num1++;num2++;num1 = a1 + num1;};fun4(0, 1);return 0;
}

总结

Lambda表达式是C++11重要的特性,使得代码变得更加简洁,易于维护,但是同时也可能导致影响性能,因此使用的时候要注意应用场景。

  1. [capture list] (params list) 关键字-> return type {function body}
  2. captrue list:捕获外部变量列表(选填)
  3. params list:形参列表(可省略)
  4. 关键字:mutable,exception,attribute(可省略)
  5. return type:返回类型(可省略)
  6. function body:函数体

其中:

mutable说明lambda表达式体内的代码可以修改被捕获的变量,并且可以访问被捕获的对象的non-const方法。

exception说明lambda表达式是否抛出异常以及何种异常。

attribute用来声明属性。

特点:

​ 一次性使用

作用:

  • 总体上:代码完整性
  • 局部:闭包是的传参数更容易

最后,最后
如果觉得有用,麻烦三连👍⭐️❤️支持一下呀,希望这篇文章可以帮到你,你的点赞是我持续更新的动力

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

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

相关文章

【Django 网页Web开发】05. 数据库操作,实战用户管理(保姆级图文)

目录1. 安装第三方模块2. ORM2.1 自己手动创建数据库2.2 django连接数据库2.3 建表语句写在哪里&#xff1f;2.4 建表语句写好后如何运行生效&#xff1f;3. 操作表3.1 创建数据表3.2 修改数据表4. 操作数据4.1 插入数据4.2 删除数据4.3 修改数据4.4 查询数据5. 实战&#xff1…

pytest学习和使用22-allure特性 丨总览中的Environment、Categories设置以及Flaky test使用

22-allure特性 丨总览中的Environment和Categories设置1 Environment设置1.1 设置方法1.2 创建文件2 Categories设置2.1 设置方式2.2 创建文件3 关于Flaky test3.1 Flaky test介绍3.2 产生Flaky Tests的原因3.3 Flaky安装3.4 Flaky使用3.5 小结小结1小结2如下图&#xff0c;我们…

开始学习HTML5

HTML5 简介 HTML5是HTML最新的修订版本&#xff0c;2014年10月由万维网联盟&#xff08;W3C&#xff09;完成标准制定。 HTML5的设计目的是为了在移动设备上支持多媒体。 HTML5简单易学。 什么是 HTML5? HTML5 是下一代 HTML 标准。 HTML , HTML 4.01的上一个版本诞生于 1…

如何将3张图片横向拼在一起

如何将3张图片横向拼在一起&#xff1f;遇到这个情况你可能马上就会说出很多图片处理的app&#xff0c;比如用某秀秀来操作&#xff0c;但是也有很多时候某秀秀也处理不了的。当我们的图片非常大&#xff0c;图片数量很多&#xff0c;图片的格式不是jpg那种通用的格式&#xff…

如何监控和诊断JVM堆内和堆外内存使用?

第26讲 | 如何监控和诊断JVM堆内和堆外内存使用&#xff1f; 上一讲我介绍了 JVM 内存区域的划分&#xff0c;总结了相关的一些概念&#xff0c;今天我将结合 JVM 参数、工具等方面&#xff0c;进一步分析 JVM 内存结构&#xff0c;包括外部资料相对较少的堆外部分。 今天我要…

Java栈和队列·下

Java栈和队列下2. 队列(Queue)2.1 概念2.2 实现2.3 相似方法的区别2.4 循环队列3. 双端队列 (Deque)3.1 概念4.java中的栈和队列5. 栈和队列面试题大家好&#xff0c;我是晓星航。今天为大家带来的是 Java栈和队列下 的讲解&#xff01;&#x1f600; 继上一个讲完的栈后&…

视听场景理解经典任务

文章目录1. 视听场景理解简介2. 主要任务2.1 Audio-visual Event Localization (AVE) 2.2 Audio-visual Video Parsing &#xff08;AVVP&#xff09;2.3 Audio-visual Question Answering &#xff08;AVQA&#xff09;2.4 Audio-visual Segmentation &#xff08;AVS&#xf…

STM32中systick中断的优先级

1、systick中断的优先级 systick为内核外设中断&#xff0c;与普通外设中断的优先级有些区别&#xff0c;并没有抢占优先级和子优先级的说法。 对于M3来说内核外设的中断优先级由内核SCB这个外设的寄存器&#xff1a;SHPRx&#xff08;x1.2.3&#xff09;来配置。 内核外设的中…

佳明安夺(Garmin Enduro)续航简单测试

文章目录&#xff08;一&#xff09;结论&#xff08;二&#xff09;测试条件&#xff08;2.1&#xff09;Garmin Connect APP 日历&#xff08;2.2&#xff09;具体运动记录&#xff08;2.3&#xff09;步数情况&#xff08;三&#xff09;补充和探讨&#xff08;3.1&#xff…

信捷PLC通过EtherCat与松下伺服通讯时的断电重启时会产生巨大异响的Bug原因及解决办法

信捷PLC支持ethercat通讯协议,可以和支持ethercat的从站通讯,像伺服驱动器或IO站点等。 其中,信捷XLH系列PLC在与松下伺服驱动器通讯时,有一个比较严重的问题,就是PLC断电再上电时,有时候会出现bug,这个bug的现象是,使用PLC的指令方式去控制伺服轴动作时,会产生巨大的…

kali内置超好用的代理工具proxychains

作者&#xff1a;Eason_LYC 悲观者预言失败&#xff0c;十言九中。 乐观者创造奇迹&#xff0c;一次即可。 一个人的价值&#xff0c;在于他所拥有的。所以可以不学无术&#xff0c;但不能一无所有&#xff01; 技术领域&#xff1a;WEB安全、网络攻防 关注WEB安全、网络攻防。…

Mybatis的课程总结

1.mybatis Mybatis主要是对代码进行少写&#xff0c;分别加入核心配置文件和mapper映射文件&#xff0c; 核心配置文件主要是为了连接数据库&#xff0c;mapper映射文件是为了编写sql语句 1.如何配置mybatis ①先创建一个moudle ②然后配置jar包 ③然后进行mybatis的分层 bean…

pcb成型板aoi检测,6种PCB板常用的检测方法

6种PCB板常用的检测方法&#xff0c;主要包括&#xff1a;PCB板人工目测、PCB板在线测试、PCB板功能测试、自动光学检测、自动X光检查、激光检测系统1、PCB板人工目测使用放大镜或校准的显微镜&#xff0c;利用操作人员视觉检查来确定电路板合不合格&#xff0c;并确定什么时候…

我们再次看看 ARB 女巫空投策略,做到知彼知己,不敢说百战不殆

女巫检测选项该项目旨在从 Arbitrum 空投中删除 Sybil 地址&#xff0c;确保只有合法用户才能收到空投代币。方法我们使用链上数据来识别同一用户拥有的相关地址&#xff0c;并使用来自 Nansen、Hop 和 OffChain Labs 的数据删除实体地址&#xff0c;例如网桥、交易所和智能合约…

Verilog学习之触发器与modelsim仿真

目录 一、前言 二、触发器介绍 三、测试文件代码 一、前言 ​ ​本文将学习常见类型触发的verilog编写&#xff0c;结合仿真结果来熟悉。 二、触发器介绍 ​ ​触发器在verilog中的作用主要是具有存储作用&#xff0c;由时钟信号来触发改变存储内容&#xff0c;较常见…

银河麒麟v10系统硬盘挂载

一、查看磁盘 近期由于centos系统停止更新用户服务器要更换银河麒麟v10&#xff0c;拿到服务器后使用lsblk -f或fdisk -l命令查看磁盘名称 可以看到sdb200G就是要挂载的硬盘&#xff0c;还没有uuid需要初始化才可以挂载。 二、分区 分区命令&#xff1a; fdisk /dev/【你的…

【LeetCode每日一题】——面试题17.21.直方图的水量

文章目录一【题目类别】二【题目难度】三【题目编号】四【题目描述】五【题目示例】六【解题思路】七【时间频度】八【代码实现】九【提交结果】一【题目类别】 双指针 二【题目难度】 困难 三【题目编号】 面试题17.21.直方图的水量 四【题目描述】 给定一个直方图(也称…

Java解题--练习解题阶段(无序阶段)-ALGO-1006 拿金币

题目算法训练 拿金币资源限制内存限制&#xff1a;256.0MB C/C时间限制&#xff1a;1.0s Java时间限制&#xff1a;3.0s Python时间限制&#xff1a;5.0s问题描述有一个N x N的方格,每一个格子都有一些金币,只要站在格子里就能拿到里面的金币。你站在最左上角的格子里,每次可以…

什么是装箱?什么是拆箱?装箱和拆箱的执行过程?常见问题?

参考答案 1、什么是装箱&#xff1f;什么是拆箱&#xff1f; 装箱&#xff1a;基本类型转变为包装器类型的过程。 拆箱&#xff1a;包装器类型转变为基本类型的过程。 //JDK1.5之前是不支持自动装箱和自动拆箱的&#xff0c;定义Integer对象&#xff0c;必须 Integer i new…

MATLAB | R2023a更新了哪些好玩的东西

R2023a来啦&#xff01;&#xff01;废话不多说看看新版本有啥有趣的玩意和好玩的特性叭&#xff01;&#xff01;把绘图放最前面叭&#xff0c;有图的内容看的人多。。 1 区域填充 可以使用xregion及yregion进行区域填充啦&#xff01;&#xff01; x -10:0.25:10; y x.^…