C++ Lambda表达式的完整介绍

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

什么是Lambda表达式

最常见的lambda的表达式写法如下

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

这里只是计算两个数的和,我们一般情况下肯定是不会这么用的,更多的时候,我们都是和stl的一些算法结合使用,例如自定义一个结构体的排序规则和打印。

struct Item
{Item(int aa, int bb) : a(aa), b(bb) {} int a;int b;
};int main()
{std::vector<Item> vec;vec.push_back(Item(1, 19));vec.push_back(Item(10, 3));vec.push_back(Item(3, 7));vec.push_back(Item(8, 12));vec.push_back(Item(2, 1));// 根据Item中成员a升序排序std::sort(vec.begin(), vec.end(),[] (const Item& v1, const Item& v2) { return v1.a < v2.a; });// 打印vec中的item成员std::for_each(vec.begin(), vec.end(),[] (const Item& item) { std::cout << item.a << " " << item.b << std::endl; });return 0;
}

这样的写法让我们代码更加简洁、清晰,可读性更强。

在c++的官方文档中,给出了lamda表达式的四种写法,这里知乎的排版有点难用,所以直接在官方文档上截了一个图。

下面介绍一下lambda的四种表达式的含义,以及表达式中各个成分的,其实说白就是在自己理解的基础上翻译一下官方文档。

四种表达式的含义

(1)完整的lambda表达式,包含了lambda表达式的所有成分。

(2)常量lambda表达式,捕获的变量都是常量,不能在lambda表达式的body中进行修改。

(3)和(2)基本一致,唯一的区别就是,lambda表达式的函数返回值可以通过函数体推导出来。一般情况函数返回值类型明确或者没有返回值的情况下可以这样写。

(4)lambda表达式的函数没有任何参数,但是可以添加lambda-specifiers,lambda-specifiers是什么我们后续再介绍。

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 函数体,函数的具体逻辑。

捕获列表

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

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

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

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

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

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

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

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

#include <iostream>int main()
{int a = 3;int b = 5;// 按值来捕获auto func1 = [a] { std::cout << a << std::endl; };func1();// 按值来捕获auto func2 = [=] { std::cout << a << " " << b << std::endl; };func2();// 按引用来捕获auto func3 = [&a] { std::cout << a << std::endl; };func3();// 按引用来捕获auto func4 = [&] { std::cout << a << " " << b << std::endl; };func4();
}

编译器如何看待Lambda表达式

我们把lambda表达式看成一个函数,那编译器怎么看待我们协的lambda呢?

其实,编译器会把我们写的lambda表达式翻译成一个类,并重载 operator()来实现。比如我们写一个lambda表达式为

auto plus = [] (int a, int b) -> int { return a + b; }
int c = plus(1, 2);

那么编译器会把我们写的表达式翻译为

// 类名是我随便起的
class LambdaClass
{
public:int operator () (int a, int b) const{return a + b;}
};LambdaClass plus;
int c = plus(1, 2);

调用的时候编译器会生成一个Lambda的对象,并调用opeartor ()函数。(备注:这里的编译的翻译结果并不和真正的结果完全一致,只是把最主要的部分体现出来,其他的像类到函数指针的转换函数均省略

上面是一种调用方式,那么如果我们写一个复杂一点的lambda表达式,表达式中的成分会如何与类的成分对应呢?我们再看一个 值捕获 例子。

int x = 1; int y = 2;
auto plus = [=] (int a, int b) -> int { return x + y + a + b; };
int c = plus(1, 2);

编译器的翻译结果为

class LambdaClass
{
public:LambdaClass(int xx, int yy): x(xx), y(yy) {}int operator () (int a, int b) const{return x + y + a + b;}private:int x;int y;
}int x = 1; int y = 2;
LambdaClass plus(x, y);
int c = plus(1, 2);

其实这里就可以看出,值捕获时,编译器会把捕获到的值作为类的成员变量,并且变量是以值的方式传递的。需要注意的时,如果所有的参数都是值捕获的方式,那么生成的operator()函数是const函数的,是无法修改捕获的值的,哪怕这个修改不会改变lambda表达式外部的变量,如果想要在函数内修改捕获的值,需要加上关键字 mutable。向下面这样的形式。

int x = 1; int y = 2;
auto plus = [=] (int a, int b) mutable -> int { x++; return x + y + a + b; };
int c = plus(1, 2);

我们再来看一个引用捕获的例子。

int x = 1; int y = 2;
auto plus = [&] (int a, int b) -> int { x++; return x + y + a + b;};
int c = plus(1, 2);

编译器的翻译结果为

class LambdaClass
{
public:LambdaClass(int& xx, int& yy): x(xx), y(yy) {}int operator () (int a, int b){x++;return x + y + a + b;}private:int &x;int &y;
};

我们可以看到以引用的方式捕获变量,和值捕获的方式有3个不同的地方:1. 参数引用的方式进行传递; 2. 引用捕获在函数体修改变量,会直接修改lambda表达式外部的变量;3. opeartor()函数不是const的。

针对上面的集中情况,我们把lambda的各个成分和类的各个成分对应起来就是如下的关系:

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

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

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

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

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

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

参考文章:

Lambda expressions

C++ Lambda 编译器实现原理

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

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

相关文章

【番外】在Windows安装Airsim/UE4踩坑合集

在Windows安装Airsim/UE4踩坑合集 1.安装过程中一定要确保Epic Games Launcher是英文环境&#xff0c;保存路径什么的也尽量是英文。2.UE4中的虚幻引擎一定要安装4.27版本以上的&#xff0c;不然的话最后运行vs的时候会报语法错误&#xff0c;网上根本查不到的那种错误。换了版…

代码随想录 213. 打家劫舍 II

题目 你是一个专业的小偷&#xff0c;计划偷窃沿街的房屋&#xff0c;每间房内都藏有一定的现金。这个地方所有的房屋都 围成一圈 &#xff0c;这意味着第一个房屋和最后一个房屋是紧挨着的。同时&#xff0c;相邻的房屋装有相互连通的防盗系统&#xff0c;如果两间相邻的房屋在…

Servlet技术之Listener监听器

系列文章目录 提示&#xff1a;这里可以添加系列文章的所有文章的目录&#xff0c;目录需要自己手动添加 Servlet技术之Listener监听器 提示&#xff1a;写完文章后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 系列文章目录前言一、什么是…

谷歌被曝或再次大裁员!3万员工面临被AI取代

据报道&#xff0c;继1.2万大裁员之后&#xff0c;谷歌又计划重组广告销售部门——这将导致3万名员工面临裁员的风险。 这一年的科技行业&#xff0c;可以说是从年头裁到了年尾&#xff0c;还越裁越多了。 而这次谷歌的部门重组计划&#xff0c;让打工人们发现&#xff0c;除…

运维工程师的出路:探索IT界“万金油”的职业发展之旅

运维工程师的未来之路:不只是IT界的“万金油” 当下,运维工作似乎正处在一个多事之秋,一方面他们必须应对技术的迅速更迭和业务需求的不断提升,另一方面,关于"35岁危机"的论调也不绝于耳。运维人员究竟该如何面对自己的职业生涯,以及他们的出路到底在哪里?这…

【Vulnhub 靶场】【Funbox: Scriptkiddie】【非常简单】【20210720】

1、环境介绍 靶场介绍&#xff1a;https://www.vulnhub.com/entry/funbox-scriptkiddie,725/ 靶场下载&#xff1a;https://download.vulnhub.com/funbox/Funbox11.ova 靶场难度&#xff1a;简单 发布日期&#xff1a;2021年07月20日 文件大小&#xff1a;1.3 GB 靶场作者&…

盘古信息IMS-MOM制造运营管理系统,构建生产现场管理信息系统的最佳选择

在当今高度竞争的制造行业中&#xff0c;高效的生产管理是企业成功的关键。盘古信息IMS-MOM制造运营管理系统作为一款领先的管理系统其关键特性为制造企业构建生产现场管理信息系统提供了强大的优势。IMS-MOM不仅仅是一个软件系统&#xff0c;更是一种技术和管理手段的结合&…

【Kafka】Kafka客户端认证失败:Cluster authorization failed.

背景 kafka客户端是公司内部基于spring-kafka封装的spring-boot版本&#xff1a;3.xspring-kafka版本&#xff1a;2.1.11.RELEASE集群认证方式&#xff1a;SASL_PLAINTEXT/SCRAM-SHA-512经过多年的经验&#xff0c;以及实际验证&#xff0c;配置是没问题的&#xff0c;但是业务…

第6章1-字符串及正则表达式 p63

字符串的常用方法 p63 p64 字符串是不可变数据类型 方法名描述说明str.lower()将str字符串全部转成小写字母并产生一个新的字符串&#xff0c;str字符串保持不变str.upper()将str字符串全部转成大写字母并产生一个新的字符串&#xff0c;str字符串保持不变str.split(sepNone)…

Java-Maven3.9.6:Maven依赖管理 / 安装-配置-使用

一、理解Maven Maven是一个开源的项目管理工具&#xff0c;主要用于构建和管理Java项目、依赖管理和文档生成&#xff0c;它可以自动下载所需的依赖库&#xff0c;并自动构建整个项目。理解Maven需要了解以下几个方面&#xff1a; 1. 项目对象模型&#xff08;Project Object…

7.2 uvm_resource_db in UVM

uvm_resource_db是一个类型参数化 type-parameterized的类&#xff0c;它是资源数据库顶部的一个方便层(convenience layer)。这个便利层简化了对低级数据库的访问&#xff0c;并且没有添加新功能。因此&#xff0c;uvm_resource_db不是从uvm_resource类派生的。以下uvm_resour…

Scala安装

Scala安装使用 windows安装,配置环境变量 以下载Scala2.11为例&#xff0c;操作在Windows中安装Scala。 官网下载scala2.11&#xff1a;All Available Versions | The Scala Programming Language下载好后安装。双击msi包安装,记住安装的路径。配置环境变量&#xff08;和配…

mvtec3d

以bagel为例&#xff0c;其中有calibration、 bagel # 百吉圈(硬面包)calibrationcamera_parameters.jsontestcombinedgt # 缺陷部位的分割剪影pngrgb # 原图pngxyz # tiffcontamination # 污染物同上crack同上good同上 hole同上 traingoodrgbxyzvalidationgood同traincla…

【快刊录用】Springer旗下2区,1个21天录用,12天见刊!

网络安全类SCIE ☑️期刊简介&#xff1a;IF&#xff1a;4.0-5.0&#xff0c;JCR2区&#xff0c;中科院3区 ☑️检索情况&#xff1a;SCIE 在检&#xff0c;正刊 ☑️征稿领域&#xff1a;提高安全性和隐私性的边缘/云的智能方法的研究&#xff0c;如数字孪生等 ☑️录用案…

【Qt-Qss-Style】

Qt编程指南 ■ Qss■ Style■ setStyleSheet ■ style.qss■ border■ 去除弹框背景圆角■ QProgressBar样式表 ■ Qss Qt 支持很多种常见 符号 “>”代表直属子部件&#xff0c;说明两个控件之间是父子关系。 “#”代表后面的字段是前面控件类型的名称&#xff0c;当然也可…

【小白专用】Apache下禁止显示网站目录结构的方法 更新23.12.25

给我一个网站地址&#xff0c;我点开后显示的是目录格式&#xff0c;把网站的目录结构全部显示出来了 这个显示结果不正确&#xff0c;不应该让用户看到我们的目录结构 配置文件的问题,apache配置文件里有一项可以禁止显示网站目录的配置项&#xff0c;禁止掉就好了 在apache…

MySQL集群架构搭建以及多数据源管理实战

MySQL集群架构搭建以及多数据源管理实战 ​ 数据库的分库分表操作&#xff0c;是互联网大型应用所需要面对的最核心的问题。因为数据往往是一个应用最核心的价值所在。但是&#xff0c;在最开始的时候&#xff0c;需要强调下&#xff0c;在实际应用中&#xff0c;对于数据库&a…

HarmonyOS应用抓包实战

Charles抓包原理 Charles是一个HTTP代理服务器,HTTP监视器,反转代理服务器&#xff0c;当浏览器连接Charles的代理访问互联网时&#xff0c;Charles可以监控浏览器发送和接收的所有数据。 在开发OpenHarmony/HarmonyOS应用开发时&#xff0c;我们使用的是ohos/axios来进行网络…

jsp页面bootstrap表格设置页面跳转一直在底部

首先介绍一下bootStrap和bootStrap table&#xff1a; bootStrap: Bootstrap是Twitter推出的一个用于前端开发的开源工具包。 它由Twitter的设计师Mark Otto和Jacob Thornton合作开发,是一个CSS/HTML框架。 bootStrap table: Bootstrap table 是一款基于 Bootstrap 的 jQue…

审视AI Agent:追捧、落地,和2024年的To B破局点

“十个AI应用里面&#xff0c;五个办公Agent&#xff0c;三个AIGC&#xff0c;还有两成是回春的数字人。”那么&#xff0c;Agent到底是不是大模型的AGI终局产品&#xff1f; 作者|斗斗 编辑|皮爷 出品|产业家 今年4月份&#xff0c;斯坦福和谷歌的研究者共同创建了一个…