lambda表达式 - c++11

news2024/11/20 12:38:58

文章目录:

  • lambda表达式概念
  • lambda表达式语法
  • 函数对象与lambda表达式

lambda表达式概念

lambda 表达式是 c++11 中引入的一种匿名函数,它可以在需要函数对象的地方使用,可以用作函数参数或返回值。lambda 表达式可以看作是一种局部定义的函数对象,它通常用于简化代码或实现某些特定的功能。

接下来我们举一个例子来说明为什么需要 lambda 表达式:

商品类 Goods 的定义:

struct Goods
{
	string _name;  // 名字
	double _price; // 价格
	int _count;    // 数量
};

现在,我们需要对若干商品分别按照价格和数量进行升序、降序排序。

想要对一个数据集合中的元素进行排序,可以使用 sort 函数,但是这里的待排序元素是自定义类型,因此需要用户自定义排序的比较规则。控制 sort 函数的比较方式通常有两种方法:1. 对商品类的 () 运算符进行重载; 2. 通过仿函数指定比较方式。

下面使用仿函数的方式来完成上述的排序:

struct Goods
{
	Goods(const char* str, double price, int count)
		:_name(str)
		,_price(price)
		,_count(count)
	{}

	string _name;
	double _price;
	int _count;
};

struct ComparePriceLess
{
	bool operator()(const Goods& gl, const Goods& gr)
	{
		return gl._price < gr._price;
	}
};

struct ComparePriceGreater
{
	bool operator()(const Goods& gl, const Goods& gr)
	{
		return gl._price > gr._price;
	}
};

struct CompareNumLess
{
	bool operator()(const Goods& gl, const Goods& gr)
	{
		return gl._count < gr._count;
	}
};

struct CompareNumGreater
{
	bool operator()(const Goods& gl, const Goods& gr)
	{
		return gl._count > gr._count;
	}
};

int main()
{
	vector<Goods> v = { { "苹果", 2.1, 50 }, { "香蕉", 3, 40 }, { "草莓", 2.2,30 }, { "菠萝", 1.5, 40 },{"芒果",2.5,120} };
	sort(v.begin(), v.end(), ComparePriceLess());
	sort(v.begin(), v.end(), ComparePriceGreater());
	sort(v.begin(), v.end(), CompareNumLess());      
	sort(v.begin(), v.end(), CompareNumGreater()); 
}

使用仿函数可以解决自定义类型的排序问题,在大型项目中,有可能仿函数的定义位置和使用仿函数的位置可能会相隔很远,所以仿函数的命令必须要通俗易懂,否则会降低代码的可读性和可维护性。

随着 c++ 语法的发展,人们觉得上面的写法太复杂了,每次为了实现一个 algorithm 算法,都需要重新去写一个类,如果每次比较的逻辑不一样,还需要去实现多个类,特别是相同类的命名。因此,c++11 中出现了 lambda 表达式。

使用 lambda 表达式完成上面要求,如下:

struct Goods
{
	Goods(const char* str, double price, int count)
		:_name(str)
		,_price(price)
		,_count(count)
	{}

	string _name;
	double _price;
	int _count;
};

int main()
{
	vector<Goods> v = { { "苹果", 2.1, 50 }, { "香蕉", 3, 40 }, { "草莓", 2.2,30 }, { "菠萝", 1.5, 40 },{"芒果",2.5,120} };
	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._count < g2._count;});
	sort(v.begin(), v.end(), [](const Goods& g1, const Goods& g2) {return g1._count > g2._count;});
}

在这个代码示例中,使用 lambda 表达式作为 sort 函数的第三个参数,可以方便地根据不同的排序标准对 vector 中的 Goods 对象进行排序,而不需要单独定义多个比较函数。这样可以减少代码量和提高代码的可读性,同时节省定义函数的时间和空间开销。

lambda表达式语法

lambda 表达式的书写格式:[capture-list] (parameters) mutable -> return-type { statement }

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

注意:在 lambda 函数定义中,参数列表和返回值类型都是可选部分,而捕捉列表和函数体可以为空。因此,c++11 中最简单的 lambda 函数为:[]{}:但该 lambda 函数不能做任何事情。

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

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

说明:

  • 父作用域指包含 lambda 函数的语句块。
  • 语法上捕捉列表可由多个捕捉项组成,并以逗号分隔。 如:[=,&a,&b] 以引用传递的方式捕捉变量 a 和 b,指传递方式捕捉其它所有变量,[&,a,this] 值传递方式捕捉变量 a 和 this,引用方式捕捉其它变量。
  • 捕捉列表不允许变量重复传递,否则会导致编译报错。 如:[=,a]:= 已经以值传递方式捕捉了所有变量,捕捉 a 重复了。
  • 在块作用域以外的 lambda 函数捕捉列表必须为空。
  • 在块作用域中的 lambda 函数仅能捕捉父作用域中局部变量,捕捉任何非此作用域或者非局部变量都会导致编译报错。
  • lambda 表达式之间不能相互赋值,即使看起来类型相同。

lambda 表达式使用示例:

int main()
{
	// 最简单的lambda表达式,该lambda表达式没有任何意义
	[] {};

	// 省略参数列表和返回值类型,返回值类型由编译器推导为int
	int a = 4, b = 7;
	[=] {return a + b;};

	// 省略了返回值类型,无返回值类型
	auto func1 = [&](int c) {b = a + c;};
	func1(12);
	cout << a << " : " << b << endl;

	// 各部分都完善的lambda函数
	auto func2 = [=, &b](int c)->int {return b += a + c;};
	cout << func2(45) << endl;

	// 复制捕捉x
	int x = 5;
	auto add_x = [x](int a) mutable {x *= 2;return a + x;};
	cout << add_x(10) << endl;
	return 0;
}

以下代码演示了 lambda 函数的拷贝构造以及如何将 lambda 表达式赋值给函数指针:

void (*pfunc)();

int main()
{
	auto f1 = [] {cout << "lambda" << endl;};
	auto f2 = [] {cout << "lambda" << endl;};

	// f1 = f2; // 编译失败,提示找不到operator=()
	
	// 允许使用一个lambda表达式拷贝构造一个新的副本
	auto f3(f2);
	f3();

	// 可以将lambda表达式赋值给相同类型的函数指针
	pfunc = f2;
	pfunc();
	return 0;
}

函数对象与lambda表达式

函数对象,又称为仿函数,即可以像函数一样使用的对象,就是在类中重载了 operator() 运算符的对象。

如下所示,分别使用函数对象和 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);
	
	// lambda
	auto r2 = [=](double monty, int year)->double {return monty * rate * year;};
	r2(10000, 2);
	return 0;
}

从使用方式来说,函数对象和 lambda 表达式一样。函数对象以 rate 作为其成员变量,在定义对象时给出初始值即可,lambda 表达式通过捕获列表可以直接对该变量进行捕获。

在这里插入图片描述

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

lambda 表达式的优势有:

  • 使代码更加简洁,易读和易于维护。
  • 可以捕获外部变量,使得 lambda 表达式更加灵活。
  • 可以作为函数对象传递,使得函数式编程更加方便。

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

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

相关文章

mysql之用户管理、权限管理、密码管理

用户管理 创建用户create user 杨20.0.0.13 identified by 123; 用户重命名rename user 杨20.0.0.13 to yang20.0.0.13; 删除用户drop user 杨20.0.0.13; 权限管理 查看用户权限show grants for 杨20.0.0.13; 赋予用户权限grant all privileges on *.* to 杨localhost id…

文章导读助你高效成长

文章目录 Java基础篇MySQL数据库篇Redis缓存篇 &#x1f4d5;我是廖志伟&#xff0c;一名Java开发工程师、Java领域优质创作者、CSDN博客专家、51CTO专家博主、阿里云专家博主、清华大学出版社签约作者、产品软文创造者、技术文章评审老师、问卷调查设计师、个人社区创始人、开…

超低直流电阻测试仪

KDZD5510半导体体积电阻率测试仪是一款针对超低直流电阻测试专门设计开发的一款高精度测试仪&#xff0c;界面清爽、操作便捷&#xff1b;量程范围为&#xff1a;0.01uΩ~10MΩ&#xff1b;显示位数为五位半&#xff1b;自动双向电流测试&#xff0c; 同时脉冲式的测试方式避免…

医院室内地图导航技术分析与作用

随着科技的不断发展&#xff0c;医疗行业的服务水平也在逐步提高。为了方便患者和医务人员&#xff0c;医院室内地图导航技术应运而生。这种技术运用了多种元素&#xff0c;包括模型地图、室内3D电子地图、路线指引、对接医院系统、位置分享和寻车导航等&#xff0c;为医院提供…

Three.js 开发引擎的特点

Three.js 是一个流行的开源 3D 游戏和图形引擎&#xff0c;用于在 Web 浏览器中创建高质量的三维图形和互动内容。以下是 Three.js 的主要特点和适用场合&#xff0c;希望对大家有所帮助。北京木奇移动技术有限公司&#xff0c;专业的软件外包开发公司&#xff0c;欢迎交流合作…

Python3,区区5行代码,制作期待的图表,这技能值得拥有(二)。

1、引言 小屌丝&#xff1a;鱼哥&#xff0c;这次按脚还不错&#xff1f; 小鱼&#xff1a;你说呢~ 小屌丝&#xff1a;那seabornde还记得&#xff1f; 小鱼&#xff1a;昂&#xff0c; 有印象 小屌丝&#xff1a;那咱开始整&#xff1f; 小鱼&#xff1a;这个… 行吧 小屌丝&…

ctfshow-web入门37-52

include($c);表达式包含并运行指定文件。 使用data伪协议 ?cdata://text/plain;base64,PD9waHAgc3lzdGVtKCdjYXQgZmxhZy5waHAnKTs/Pg PD9waHAgc3lzdGVtKCdjYXQgZmxhZy5waHAnKTs/Pg 是<?php system(cat flag.php);?> base64加密 源代码查看得到flag 38 多禁用了ph…

订水商城实战教程-06店铺信息

目录 1 创建数据源2 生成管理后台3 创建腾讯地图API4 配置小程序5 地址组件配置地图API6 显示店铺名称总结 上一篇我们介绍了权限控制&#xff0c;本篇我们就开始首页开发了。首页先需要显示店铺的名称&#xff0c;我们需要将店铺的信息存入数据源中。 1 创建数据源 打开控制台…

计组之存储系统

存储器概述 分类 1.按在计算机中的作用&#xff08;层次&#xff09;分类 主存储器。CPU可以直接随机地对其进行访问&#xff0c;也可以和高速缓冲存储器&#xff08;Cache)及辅助存储器交换数据。辅助存储器。辅存的内容需要调入主存后才能被CPU访问。高速缓冲存储器。位于…

电脑办公最佳拍档 夸克网盘升级低耗能备份、PDF阅读器等功能

临近年终&#xff0c;上班族不仅要总结过去一年的成绩还要开始制定新规划&#xff0c;在这个过程中整理资料是必不可少的环节。对于经常需要使用文件备份和PDF的用户&#xff0c;推荐大家试一下夸克网盘电脑端&#xff0c;升级后的“低耗能备份”和“PDF阅读器”让备份体验更丝…

Python 算法高级篇:最短路径算法的优化

Python 算法高级篇&#xff1a;最短路径算法的优化 引言 1. Dijkstra 算法2. Bellman-Ford 算法3. SPFA 算法4. 优化与比较5. 案例分析&#xff1a;地理导航6. 总结 引言 最短路径算法是图算法中的一个重要领域&#xff0c;它用于查找从一个起始节点到目标节点的最短路径。在这…

2.1 点纹理背景

快速复制——设置背景纹理 然后填充为淡蓝色&#xff0c;无轮廓&#xff0c;纹理背景就做好了

阿里云2023年双11活动,云服务器价格出炉,2核2G云服务器99元/年!

阿里云2023年双11期间推出了金秋云创季活动&#xff0c;新老用户均可领取上云满减券礼包&#xff0c;单笔订单最高减2400元&#xff0c;还有多款爆品超低折扣&#xff0c;2核2G云服务器99元/年&#xff0c;续费不涨价&#xff0c;新老用户同享&#xff01; 一、阿里云双11活动地…

arcgispro中机器学习部分

参考链接 arcgis.learn 模块 |ArcGIS API for Python arcgis包位置 安装路径\GeoScene\Pro\bin\Python\envs\arcgispro-py3\Lib\site-package\arcgis 以automl进行训练工具为例&#xff0c;工具导入模块中涉及机器学习的模块 该模块所在位置 安装路径\GeoScene\Pro\bin\Py…

解决ping: www.baidu.com: Name or service not known

配置了静态ip后&#xff0c;ping不通外网的问题 1、修改网络配置文件 修改你所用的网卡的配置信息&#xff1a;主要配置红框的内容 ONBOOTyes DNS1114.114.114.114 DNS28.8.8.82、重启网络服务systemctl restart network 3、修改DNS配置文件 修改&#xff1a;vi /etc/reso…

6西格玛质量标准: 提升业务效率的关键

在现代竞争激烈的商业环境中&#xff0c;企业需要不断提高效率&#xff0c;降低成本&#xff0c;同时确保产品和服务的质量。为了达到这个目标&#xff0c;许多企业已经转向了6西格玛质量标准。这个方法旨在通过最小化缺陷和提高流程稳定性来优化业务运作&#xff0c;为客户提供…

2.3.2 交换机的STP技术

实验2.3.2 交换机的STP技术 一、任务描述二、任务分析三、具体要求四、实验拓扑五、任务实施1.交换机的基本配置。2.开启交换机的STP。3.配置SW3A和SW3B上STP的优先级。将SW3A配置为根交换机&#xff0c;SW3B配置为备用根交换机。 六、任务验收七、任务小结 一、任务描述 由于…

【C++】引用(取别名)

&#x1f4d9; 作者简介 &#xff1a;RO-BERRY &#x1f4d7; 学习方向&#xff1a;致力于C、C、数据结构、TCP/IP、数据库等等一系列知识 &#x1f4d2; 日后方向 : 偏向于CPP开发以及大数据方向&#xff0c;欢迎各位关注&#xff0c;谢谢各位的支持 引用 1. 引用概念2. 引用特…

要是能重来,你还会选择程序员吗?

昨天面试了2个应届毕业生&#xff0c;一男一女&#xff0c;男的我觉得技术还可以&#xff0c;就录了&#xff0c;女的没有通过&#xff0c;完事后我去厕所边上的楼道抽烟&#xff0c;却发现女孩子蹲在地上哭的一塌糊涂。 我听得很清楚她跟那个男同学说的话&#xff0c;她已经忘…