C++11 -- lambda表达式

2023-10-27

lamaba表达式的引入

  • 在C++11之前,如果我们想对自定义类型Goods排序,可以根据姓名,价格,学号按照从大到小或者从小到大的方式排序,可是,这样我们要写额外写6个相关的仿函数.
  • 并且我们在对自定义仿函数命名的过程中,很容易会因为命名不规范造成代码解读麻烦,无法通过仅仅通过仿函数名字了解实际功能,只能重新去查找对应的函数名的仿函数去了解实际功能.
struct Goods
{
	string _name;  //名字
	double _price; //价格
	int _num;      //数量
};

struct ComparePriceLess
{
	bool operator()(const Goods& g1, const Goods& g2)
	{
		return g1._price < g2._price;
	}
};
struct ComparePriceGreater
{
	bool operator()(const Goods& g1, const Goods& g2)
	{
		return g1._price > g2._price;
	}
};
struct CompareNumLess
{
	bool operator()(const Goods& g1, const Goods& g2)
	{
		return g1._num < g2._num;
	}
};
struct CompareNumGreater
{
	bool operator()(const Goods& g1, const Goods& g2)
	{
		return g1._num > g2._num;
	}
};
int main()
{
	vector<Goods> v = { { "苹果", 2, 20 }, { "香蕉", 3, 30}, { "橙子", 4,40 }, { "菠萝", 5,50 } };
	sort(v.begin(), v.end(), ComparePriceLess());    //按Goods价格升序排序
	sort(v.begin(), v.end(), ComparePriceGreater()); //按Goods价格降序排序
	sort(v.begin(), v.end(), CompareNumLess());      //按Goods升序排序
	sort(v.begin(), v.end(), CompareNumGreater());   //按Goods降序排序
	return 0;
}


在C++11后,我们便可以通过lamada表达式来解决,lamada表达式实际上就是一个匿名函数,这样我们即可通过lamada表达式直接了解sort排序的比较方式,进而提高了代码的可读性.

int main()
{
	vector<Goods> v = { { "苹果", 2.1, 300 }, { "香蕉", 3.3, 100 }, { "橙子", 2.2, 1000 }, { "菠萝", 1.5, 1 } };
	sort(v.begin(), v.end(), []( const Goods& g1,const Goods& g2) {return g1._price < g2._price; });
	sort(v.begin(), v.end(), [](const Goods& g1, const Goods& g2) {return g1._price < g2._price; });
	sort(v.begin(), v.end(), [](const Goods& g1, const Goods& g2) { return g1._num < g2._num; });
	sort(v.begin(), v.end(), [](const Goods& g1, const Goods& g2) { return g1._num < g2._num; });
	return 0;
}


lambda表达式语法

lamada表达式的书写格式:

[capture-list] (parameters) mutable -> return-type 
{  
  statement
}

lamabda达式各部分说明

  • [capture-list]: 捕捉列表,该列表总是出现在lambda表达式的开始位置,编译器会根据[]来判断接下来的代码是否为lambda表达式, 捕捉列表能够根据上下文中的变量让lambda表达式使用.
  • (parameters): 参数列表,与普通的参数列表一致,如果不需要传递参数,则可以来连同()一起省略.
  • mutable: 默认情况下,lambda表达式总是一个const函数(函数形参不可以被修改),而mutable可以取消常量性,在使用该修饰符时,参数列表是不可以省略的(即使参数列表为空.
  • ->returntype: 返回值类型.,一般由于编译器对返回类型进行推导,在返回值明确的情况下,可以省略.
  • {statement}: 函数体.在该函数体内,除了可以使用函数体内的形参外,还可以使用所有被捕获到的变量.

lambda表达式的简单运用

int mian()
{
	//由于lambda表达式实际上就是一个匿名对象,没有函数名不好调用,但是我们可以通过auto自动获取.
	auto add1 = [](int a, int b) { return a + b; };    //省略返回值.

	cout << add1(1, 2) << endl;

}

捕获列表说明

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

  • [var]:表示值传递方式捕捉变量var.
  • [=]:表示值传递方式捕获所有父作用域中的变量(包括this).
  • [&var]:表示引用传递捕捉变量var.
  • [&]:表示引用传递捕捉所有父作用域中的变量(包括this).
  • [this]:表示值传递方式捕捉当前的this指针.

lambda表达式中未使用捕获列表和使用捕获列表对比.

如果我们不适用捕获列表,我们就要额外写函数形参,在调用时也必须将实参传过去,这样过于麻烦.

int main()
{
	//之前做法
	int x = 0,y = 1;
	
	auto swap1 = [](int& x1, int& x2) { int tmp = x1; x1 = x2; x2 = tmp;};

	swap1(x, y);

	return 0;
}

所以,我们可以使用捕获列表,又因为传值捕获过来的x,y通常是不可以被修改的(可以使用mutable修饰符),并且此时捕获过来的x,y仅仅为实参的拷贝,此时,我们一般采用引用捕捉,这样让代码更加简洁.


int main()
{
	auto swap2 = [&x, &y] {int tmp = x; x = y; x = tmp;}; //引用捕捉.
    
	swap2();             //不需要传递实参.
	
	cout << x << ":" << y << endl;
	
}

捕捉列表其他特性的简单运用

int main()
{
	int a, b, c, d, e;
	
	auto f1 = [=] {cout << a << b << d << e; }; //a,b,c,d,e全部传值捕获.

	f1();

	auto f2 = [=, &a] { a++; cout << a << b << c << d << e; }; //b,c,d,e传值捕获,a传引用捕获.

	f2();
	
}

但是注意,捕获列表不允许变量重复传递,否则就会导致编译错误.

int main()
{
	int a, b, c, d, e;
	
	auto f = [=,a] {cout << a << b << d << e; }; //重复捕获.

}

lamaba表达式底层原理探索

编译器对于lambda的处理,实际上和仿函数的处理一样.

为了对lambda表达式的底层原理进行验证,我们分别写了一个仿函数和一个lambda表达式,他们的功能相同.

class Rate
{
public:
	Rate(double rate) : _rate(rate)
	{}
	double operator()(double money, int year)
	{
		return money * _rate * year;
	}
private:
	double _rate;
};
int main()
{
	// 函数对象
	double rate = 0.49;
	Rate r1(rate);
	r1(10000, 2);
	// lamber表达式
	auto r2 = [=](double monty, int year)->double {return monty * rate * year;
	};
	r2(10000, 2);
	return 0;
}

当我们对仿函数和lambda表达式分别调用时,转到反汇编查看.
在这里插入图片描述

总结:

  • 从使用方式来看,仿函数与lambda表达式完全一样,函数对象将rate作为其成员变量,在定义对象时传递实参即可,lambda表达式通过捕获列表可以直接将该变量捕获到实参传过去。
  • 从底层实现的方式来看,完全就是按照仿函数的方式处理,当我们定义一个lambda表达式时,编译器就会主动生成一个仿函数,并且,为了方便处理,编译器都要通过UUID的方式基本生成一个唯一的仿函数名.然后在调用的时候通过lambda表达式调用这个仿函数,该仿函数又调用操符重载operator().所以实际上,捕获列表捕获到的变量传递给了operator()后在函数体内实现.
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++11 -- lambda表达式 的相关文章

  • 捕获 .aspx 和 .ascx 页面中的异常

    问题说明了一切 请看以下示例代码 ul li li ul
  • 无法继承形状

    为什么我不能使用继承 a 的类Shapes class http msdn microsoft com en us library ms604615 28v vs 90 29 我需要延长Rectangle具有一些方法的类 但我想以与使用相同
  • 如何在 C# 中将 Json 转换为对象

    我想将 Json 转换为 C 中的对象 这里的 Json 是 值 e920ce0f e3f5 4c6f 8e3d d2fbc51990e4 如何使用 Object 问题看似愚蠢 但其实并不那么愚蠢 我没有简单的 Json 我有 IEnume
  • Android NDK 代码中的 SIGILL

    我在市场上有一个 NDK 应用程序 并获得了有关以下内容的本机崩溃报告 SIGILL信号 我使用 Google Breakpad 生成本机崩溃报告 以下是详细信息 我的应用程序是为armeabi v7a with霓虹灯支持 它在 NVIDI
  • MVC 5 中具有 ASP.NET Identity 的 Autofac 不会验证 OWIN 管道中的安全标记

    我在 MVC 5 中设置了 AutoFac 来与 ASP NET Identity 一起使用 表面上一切似乎都工作正常 即用户可以创建帐户并登录 但后来我发现 当安全标记更改时 用户不会注销 通过在 AspNetUsers 表中进行暴力破解
  • 保证复制省略是否适用于函数参数?

    如果我理解正确的话 从 C 17 开始 这段代码现在要求不进行任何复制 Foo myfunc void return Foo auto foo myfunc no copy 函数参数也是如此吗 下面的代码中的副本会被优化掉吗 Foo myf
  • wordexp 失败时我们需要调用 wordfree 吗?

    wordexp 失败时我们需要调用 wordfree 吗 在某些情况下 调用 wordfree 似乎会出现段错误 例如 当 wordfree 返回字符串为 foo bar 的错误代码时 这在手册页中并不清楚 我已经看到在某些错误情况下使用了
  • 让网络摄像头在 OpenCV 中工作

    我正在尝试让我的网络摄像头在 Windows 7 64 位中的 OpenCV 版本 2 2 中捕获视频 但是 我遇到了一些困难 OpenCV 附带的示例二进制文件都无法检测到我的网络摄像头 最近我发现这篇文章表明答案在于重新编译一个文件 o
  • 对于 C# Express 用户来说,有哪些好的工具可以识别可能重复的代码? [关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 也可以看看 有什么工具可以检查重复的 VB NET 代码吗 https stackoverflow c
  • ASP.NET Core 中间件与过滤器

    在阅读了 ASP NET Core 中间件之后 我对何时应该使用过滤器以及何时应该使用中间件感到困惑 因为它们似乎实现了相同的目标 什么时候应该使用中间件而不是过滤器 9频道有一个关于此的视频 ASP NET 怪物 91 中间件与过滤器 h
  • 当Model和ViewModel一模一样的时候怎么办?

    我想知道什么是最佳实践 我被告知要始终创建 ViewModel 并且永远不要使用核心模型类将数据传递到视图 这就说得通了 让我把事情分开 但什么是Model 和ViewModel一模一样 我应该重新创建另一个类还是只是使用它 我觉得我应该重
  • 读取依赖步行者输出

    I am having some problems using one of the Dlls in my application and I ran dependency walker on it i am not sure how to
  • Xamarin Forms Binding - 访问父属性

    我无法访问页面的 ViewModel 属性以便将其绑定到 IsVisible 属性 如果我不设置 BindingContext 我只能绑定它 有没有办法可以在设置 BindingContext 的同时访问页面的 viewmodel root
  • 在哪里可以找到 Microsoft.Build.Utilities.v3.5

    如何获取 Microsoft Build Utilities v3 5 我正在使用 StyleCop 4 7 Stylecop dll 中的 StyleCop msbuild 任务似乎依赖于 Microsoft Build Utilitie
  • 在 C# 的 WebAPI 中的 ApiController 上使用“传输编码:分块”提供数据

    我需要服务分块传输使用编码数据API控制器 因为我无权访问HttpContext or the Http请求 我有点不知道在哪里写入响应以及在哪里刷新它 设置如下 public class MyController ApiControlle
  • 如何从 Windows Phone 7 模拟器获取数据

    我有一个 WP7 的单元测试框架 它在手机上运行 结果相当难以阅读 因此我将它们写入 XDocument 我的问题是 如何才能将这个 XML 文件从手机上移到我的桌面上 以便我可以实际分析结果 到目前为止 我所做的是将 Debugger B
  • 如何获取带有某个属性注释的所有属性?

    我刚刚从 Roslyn 开始 我想找到所有用属性名称 OneToOne 注释的属性 我启动了 SyntaxVisualizer 并能够获取对该节点的引用 但我想知道是否有更简单的方法来实现此目的 这就是我所拥有的 var prop docu
  • Streamwriter 覆盖 txt 文件中的文本

    有没有什么方法可以重新打开流写入器而不创建新的写入对象 因为此时 当调用 WriteOdd 时 streamwriter 正在覆盖在它之前调用的 WriteEven public void WriteEven StreamWriter wr
  • winform c# 中的弹出窗口

    我正在开发一个需要弹出窗口的项目 但问题是我还希望能够通过表单设计器在此弹出窗口中添加文本框等 所以基本上我有一个按钮 当您单击它时 它将打开我在表单设计器中设计的另一个窗口 我一直在谷歌搜索 但还没有找到我需要的东西 所以我希望你们能帮助
  • 如何在 C# 中获取 CMD/控制台编码

    我需要指定正确的代码页来使用 zip 库打包文件 正如我所见 我需要指定控制台编码 在我的例子中为 866 C Users User gt mode Status for device CON Lines 300 Columns 130 K

随机推荐

  • 爬虫基础入门(4)简单模拟登录

    本节我们介绍使用爬虫进行美食杰网站的模拟登录 首先我们找到美食杰的登录界面的url以及headers cookie from urllib import request 首先我们导入request库和cookie库 from http co
  • Bubble冒泡排序

    原谅我偷懒 是真的没有什么写的内容了啊 我都好怀疑他们那些大佬是怎么那么多的文章和技术分享的 我要自闭了 时间复杂度O n2 C 的内置排序函数使用的并非冒泡而是快排 Git地址 public override void SortOrder
  • chatGPT写小游戏1分钟一个,快到起飞

    猜数字游戏的规则是电脑随机生成一个1到100之间的整数 玩家需要猜测这个数字是多少 电脑会提示玩家猜的数字是偏大还是偏小 直到猜中为止 下面是代码示例 import random num random randint 1 100 guess
  • argparse模块的用法

    argparse模块的用法 示例 创建解析器 添加参数 解析参数 ArgumentParser对象 编程 用法 说明 parents formatter class 版本3 5中的新功能 版本 3 2中的新功能 源代码 Lib argpar
  • 用神经辐射场在大场景中漫游

    目录 前言 介绍 背景 改进 NeRF 以编码大型场景 在训练数据中获得足够的观点 动态对象移除 应用 结论 参考 前言 最近一直在做NeRF相关工作 偶然看到台湾智慧实验室一篇文章 Hovering Around a Large Scen
  • 毕业设计 基于单片机的多功能遥控器设计

    0 前言 这两年开始毕业设计和毕业答辩的要求和难度不断提升 传统的毕设题目缺少创新和亮点 往往达不到毕业答辩的要求 这两年不断有学弟学妹告诉学长自己做的项目系统达不到老师的要求 为了大家能够顺利以及最少的精力通过毕设 学长分享优质毕业设计项
  • unity 获取复杂物体(模型)中心点

    Unity 获取复杂物体 模型 中心点 1 获取物体中心点 public Vector3 GetCenter GameObject target Renderer mrs target gameObject GetComponentsInC
  • 阿里云云效:代码提交使用

    最近采用阿里云的云效作为管理工具之一 确实蛮不错自动化部署自动化合并代码 但是还是有一定的不同之处 比如我今天提交代码 编码五分钟提交大半天 找了别人也不清楚什么问题 其实是搞错了人家的代码发布流程 首先提交代码第一步 云效创建分支 云效最
  • CSS实现旋转风车

    CSS实现旋转风车 使用css实现旋转风车主要是运用border和css动画来实现的 效果图如下 一 制作风车 首先观察风车是由8个相等形状大小的三角形旋转组成的 可以发现都是围绕一个中心点旋转组成的 所以我们可以先用border画出一个中
  • 系统管理员设置了系统策略禁止进行此安装怎么解决

    最近一位用户在电脑下载安装软件时 系统出现提示 系统管理员设置了系统策略 禁止进行此安装 这该怎么办呢 既然系统管理员禁止了程序安装 那么我们只要开启相应的安装权限就可以了 下面 小编给大家讲解系统管理员设置了系统策略禁止进行此安装的处理方
  • MYSQL中的CREATE TEMPORARY TABLE

    Posted on 八月 19 2008 by arrowpig1979 记录一下今天的一个BUG FIXING 早上收到一个BUG 说有一个到模块A的调用B 多执行几次以后就会出错 错误信息显示SQL ERROR 因为CDC SBE就我最
  • Parker - 最高效的自动标注工具

    http www getmarkman com http www cutterman cn zh parker
  • vue3时间插件——Moment.js使用

    在日期时间这一块在js中是有体现的 但是用起来不是特别方便 尤其是在vue框架中 我们也不可能去那样使用 显得很笨拙麻烦 所以给大家这次带来一个好用的时间插件 就是Moment时间插件 很小巧 使用也方便 也兼容vue3 下面来详细介绍一下
  • 网络层:IP协议

    本博文分享的是网络层的IP协议 从IP协议的基本概念 协议格式开始分析并分享出来 IP协议的基本概念 不同于讨论TCP UDP时只讨论通信主机之间的关系 在讨论IP协议中 会加上主机之间的网络来一起进行讨论分析 主机 一般配有IP地址 路由
  • 【vision transformer】LETR论文解读及代码实战(一)

    LETR Line Segment Detection Using Transformers without Edges 基于vision transformer DETR 提取wireframe的网络框架 截止日前实现了sota性能 论文
  • C3P0连接池的断开自动重联功能

    问题背景 Java后台日志发现Error updating database Cause com mysql jdbc exceptions jdbc4 CommunicationsException Communications link
  • 跨域问题(CORS / Access-Control-Allow-Origin)

    1 前言 最近在项目中 调用Eureka REST接口时 出现了CORS跨越问题 Cross origin resource sharing 在此与大家进行分享 避免多走些弯路 项目前端 http localhost 9000 通过Ajax
  • python对Json文件的操作

    深层嵌套的Json 使用方式 传递的是json转成str后的json data finder JsonPathFinder json data 寻找所有的cursor字段 path list finder finder find all c
  • React:阻止默认事件

    在html页面中直接通过return false即可阻止默认事件 a href 点击 a 而在react中需要使用e preventDefault function PreventDe return a href console log 阻
  • C++11 -- lambda表达式

    文章目录 lamaba表达式的引入 lambda表达式语法 lamabda达式各部分说明 捕获列表说明 lamaba表达式底层原理探索 lamaba表达式的引入 在C 11之前 如果我们想对自定义类型Goods排序 可以根据姓名 价格 学号