C++11 -- lambda表达式

news2024/12/24 2:09:21

文章目录

  • lamaba表达式的引入
  • lambda表达式语法
    • lamabda达式各部分说明
    • 捕获列表说明
  • lamaba表达式底层原理探索

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()后在函数体内实现.

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

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

相关文章

以太坊学习三: Merkle树和验证

Merkle tree简介 Merkle树又称为哈希树&#xff0c;是一种二叉树&#xff0c;由一个根节点、若干中间节点和一组叶节点组成。最底层的叶节点存储数据&#xff0c;在它之上的一层节点为它们对应的Hash值&#xff0c;中间节点是它下面两个子节点的Hash值&#xff0c;根节点是最后…

DAY 66 数据库缓存服务——NoSQL之Redis配置与优化

缓存概念 缓存是为了调节速度不一致的两个或多个不同的物质的速度&#xff0c;在中间对速度较慢的一方起到加速作用&#xff0c;比如CPU的一级、二级缓存是保存了CPU最近经常访问的数据&#xff0c;内存是保存CPU经常访问硬盘的数据&#xff0c;而且硬盘也有大小不一的缓存&am…

爆肝整理,最全单元测试-测试用例总结(全覆盖)及拿即用...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 Python自动化测试&…

Maven私服仓库配置-Nexus详解

目录 一、什么是Maven私服&#xff1f;二、Maven 私服优势三、Maven 私服搭建四、Sonatype Nexus介绍五、Nexus仓库属性和分类六、Nexus仓库配置以及创建仓库七、Nexus配置用户角色八、Maven SNAPSHOT(快照)九、项目当中配置Nexus上传依赖十、项目当中配置Nexus下载依赖十一、测…

人工智能基础部分20-生成对抗网络(GAN)的实现应用

大家好&#xff0c;我是微学AI&#xff0c;今天给大家介绍一下人工智能基础部分20-生成对抗网络(GAN)的实现应用。生成对抗网络是一种由深度学习模型构成的神经网络系统&#xff0c;由一个生成器和一个判别器相互博弈来提升模型的能力。本文将从以下几个方面进行阐述&#xff1…

flutter_学习记录_03_通过事件打开侧边栏

实现类似这样的侧边栏的效果&#xff1a; 可以用Drawer来实现。 1. 在Scaffold组件下设置endDrawer属性 代码如下&#xff1a; import package:flutter/material.dart;class ProductListPage extends StatefulWidget {ProductListPage( {super.key}) ;overrideState<Pro…

首发Yolov8优化:Adam该换了!斯坦福最新Sophia优化器,比Adam快2倍 | 2023.5月斯坦福最新成果

1.Sophia优化器介绍 斯坦福2023.5月发表的最新研究成果,他们提出了「一种叫Sophia的优化器,相比Adam,它在LLM上能够快2倍,可以大幅降低训练成本」。 论文:https://arxiv.org/pdf/2305.14342.pdf 本文介绍了一种新的模型预训练优化器:Sophia(Second-order Clippe…

低资源方面级情感分析研究综述

文章目录 前言1. 引言2. 问题定义、数据集和评价指标2.1 问题定义2.2 任务定义2.3 常用数据集 3. 方面级情感分析的方法3.1 **方面词抽取**3.1.1 基于无监督学习的方法3.1.1.1 基于规则的方面词抽取3.1.1.2 基于统计的方面词抽取 3.1.2 基于有监督浅层模型的方法3.1.3 基于有监…

【C++初阶】类和对象(下)之友元 + 内部类 + 匿名对象

&#x1f466;个人主页&#xff1a;Weraphael ✍&#x1f3fb;作者简介&#xff1a;目前学习C和算法 ✈️专栏&#xff1a;C航路 &#x1f40b; 希望大家多多支持&#xff0c;咱一起进步&#xff01;&#x1f601; 如果文章对你有帮助的话 欢迎 评论&#x1f4ac; 点赞&#x1…

一台服务器通过nginx安装多个web应用

1.首先安装nginx网站服务器 yum install nginx 2.nginx 的主配置文件&#xff1a;/etc/nginx/nginx.conf (一台服务器有两个域名部署) 我们在/etc/nginx/nginx.d/下创建一个conf文件&#xff0c;这个文件会被嵌套到主配置文件当中 server { listen 80; …

《数据库应用系统实践》------ 个人作品管理系统

系列文章 《数据库应用系统实践》------ 个人作品管理系统 文章目录 系列文章一、需求分析1、系统背景2、 系统功能结构&#xff08;需包含功能结构框图和模块说明&#xff09;3&#xff0e;系统功能简介 二、概念模型设计1&#xff0e;基本要素&#xff08;符号介绍说明&…

Netty客户端与服务器端闲暇检测与心跳检测(三)

网络应用程序中普遍存在一个问题&#xff1a;连接假死&#xff0c;连接假死现象是:在某一端(服务器端|客户端)看来,底层的TCP连接已经断开,但是应用程序没有捕获到,因此会认为这个连接还存在。从TCP层面来说,只有收到四次握手数据包,或者一个RST数据包,才表示连接状态已断开; 连…

Spring练习二ssm框架整合应用

导入教程的项目&#xff0c;通过查看源码对aop面向切面编程进行理解分析 aop面向编程就像是我们给程序某些位置丢下锚点&#xff08;切入点&#xff09;以及当走到锚点时需要调用的方法&#xff08;切面&#xff09;。在程序运行的过程中&#xff0c; 一旦到达锚点&#xff0c;…

f-stack的源码编译安装

DPDK虽然能提供高性能的报文转发&#xff08;安装使用方法见DPDK的源码编译安装&#xff09;&#xff0c;但是它并没有提供对应的IP/TCP协议栈&#xff0c;所以在网络产品的某些功能场景下&#xff08;特别是涉及到需要使用TCP协议栈的情况&#xff09;&#xff0c;比如BGP邻居…

Ansible原理简介与安装篇

工作原理 1、在Ansible管理体系中&#xff0c;存在“管理节点”和“被管理节点” 2、被管理节点通常被称为”资产“ 3、在管理节点上&#xff0c;Ansible将AdHoc或PlayBook转换为python脚本。并通过SSH将这些python脚本传递到被管理服务器上。在被管理服务器上依次执行&#xf…

遥感云大数据在灾害、水体与湿地领域及GPT模型应用

近年来遥感技术得到了突飞猛进的发展&#xff0c;航天、航空、临近空间等多遥感平台不断增加&#xff0c;数据的空间、时间、光谱分辨率不断提高&#xff0c;数据量猛增&#xff0c;遥感数据已经越来越具有大数据特征。遥感大数据的出现为相关研究提供了前所未有的机遇&#xf…

基础篇010.2 STM32驱动RC522 RFID模块之二:STM32硬件SPI驱动RC522

目录 基础篇010.1 STM32驱动RC522 RFID模块之一&#xff1a;基础知识 1. 实验硬件及原理图 1.1 RFID硬件 1.2 硬件原理图 2. 单片机与RFID硬件模块分析 3. 利用STM32CubeMX创建MDK工程 3.1 STM32CubeMX工程创建 3.2 配置调试方式 3.3 配置时钟电路 3.4 配置时钟 3.5 配…

【C++】Map、Set 模拟实现

文章目录 &#x1f4d5; 概念&#x1f4d5; 实现框架Find()★ 迭代器 ★反向迭代器map 的 operator[ ] &#x1f4d5; 源代码rb_tree.hset.hmap.h &#x1f4d5; 概念 map、set 是 C 中的关联式容器&#xff0c;由于 map 和set所开放的各种操作接口&#xff0c;RB-tree 也都提…

2023.05.28 学习周报

文章目录 摘要文献阅读1.题目2.现有方法存在的局限性3.SR-GNN模型4.模型的组成部分4.1 构图4.2 item向量表示4.3 session向量表示4.4 预测模块 5.实验与分析5.1 数据集5.2 比较方法5.3 评估指标5.4 实验结果 6.结论 有限元法1.一个例子2.进一步 深度学习1.张量场2.对流-扩散方程…

Linux(基础IO详解)

在基础IO这篇博客中&#xff0c;我们将了解到文件系统的构成&#xff0c;以及缓冲区究竟是个什么东东&#xff0c;我们都知道缓冲区&#xff0c;有时也谈论缓冲区&#xff0c;但不一定真的去深入了解过缓冲区。为什么内存和磁盘交互速度如此之慢&#xff1f;为什么都说Linux中一…