C++_lambda表达式

news2024/11/17 15:52:20

目录

前言-lambda表达式的介绍:

1、lambda表达式的作用

2、lambda表达式的优势

2.1 用lambda构建lambda变量

3、lambda表达式的类型

4、捕捉列表说明 

4.1 传值捕捉 

4.2 mutable 

4.3 传引用捕捉 

4.4 混合捕捉 

5、lambda的大小

结语 


前言-lambda表达式的介绍:

        C++11推出lambda表达式,lambda表达式实际上是一个匿名函数,他的具体书写格式如下:

        lambda格式:[capture-list] (parameters) mutable -> return-type { statement  }

        1、[capture-list]表示捕捉列表,他是lambda函数的标志性符号,编译器会根据[]来判断该式子是否为lambda函数,他的另一个作用是可以捕捉父类作用域的变量给到lambda函数使用,因此叫捕捉列表。

        2、(parameters)表示lambda的参数列表,他的用法和意义跟普通函数的形参列表是一样的,如果不需要对lambda传任何参数则可以连同括号一起省略。

        3、mutable的作用是消除捕捉列表中的常属性,因为lambda的捕捉列表中的变量都是默认被const修饰的,因此lambda函数内部是不能修改[capture-list]中的参数,但是加上mutable后就可以在函数体内部修改捕捉的参数了。注意:如果加上mutable则参数列表(parameters)必须有参数,即使参数列表为空。

        4、-> return-type表示lambda函数的返回值类型,他的意义等同于普通函数的返回类型,只不过在lambda函数中可以省略-> return-type(不管lambda函数有没有返回值都可以省略),由编译器自动推导该lambda函数的返回值类型。

        

        5、{ statement  }表示lambda的函数体,因为lambda实际上是一个匿名函数,所以他也有属于自己的函数体,并且在捕捉列表中的变量可以在该函数体内使用。

        从以上叙述可以得到一个有趣的写法,因为lambda表达式中只有捕捉列表和函数体的标识符不能省略,因此最简单的lambda函数可以写为:[]{},该lambda函数没有实现任何的功能。

1、lambda表达式的作用

        为什么会C++11会推出lambda表达式呢?因为在此之前,我们如果要自己实现一个仿函数则需要手写一个类,如果要实现的逻辑复杂而多样,则要实现多个类进行仿函数的调用,类一旦多了起来就会有重名的烦恼,并且实现的类的目的仅仅是为了的仿函数调用,难免会感到大材小用,比如以下示例: 

#define _CRT_SECURE_NO_WARNINGS 1

#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;

struct Shop
{
	string _name;//商品名字
	double _price;//价格
	int _evaluate; // 评价
	Shop(const char* str, double price, int evaluate)
		:_name(str)
		, _price(price)
		, _evaluate(evaluate)
	{}
	friend ostream& operator<<(ostream& out, const Shop& s);
	
};
ostream& operator<<(ostream& out, const Shop& s)//流提取
{
	cout << s._name << " " << s._price << " " << s._evaluate << endl;
	return out;
}
struct ComparePriceLess//价格低的优先
{
	bool operator()(const Shop& gl, const Shop& gr)
	{
		return gl._price < gr._price;
	}
};
struct ComparePriceGreater//价格高的优先
{
	bool operator()(const Shop& gl, const Shop& gr)
	{
		return gl._price > gr._price;
	}
};
int main()
{
	vector<Shop> v = { { "苹果", 12.2, 5 }, { "香蕉", 3.3, 4 }, { "橙子", 6.6,
   3 }, { "菠萝", 1.5, 4 } };
	sort(v.begin(), v.end(), ComparePriceLess());
	//打印
	for (auto num : v)
	{
		cout << num;
	}
	cout << endl;
	sort(v.begin(), v.end(), ComparePriceGreater());
	//打印
	for (auto num : v)
	{
		cout << num;
	}
	cout << endl;
}

        运行结果:

        从结果可以看到,虽然创建类调用仿函数可以有效的实现我们的要求,但是排序的逻辑不同就要再多写一个类来调用仿函数, 人们觉得该写法过于复杂,因此推出lambda表达式来代替以上的写法。

2、lambda表达式的优势

        比如以上代码,若用lambda表达式代替仿函数的类,优化后代码如下: 

#define _CRT_SECURE_NO_WARNINGS 1

#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;

struct Shop
{
	string _name;//商品名字
	double _price;//价格
	int _evaluate; // 评价
	Shop(const char* str, double price, int evaluate)
		:_name(str)
		, _price(price)
		, _evaluate(evaluate)
	{}
	friend ostream& operator<<(ostream& out, const Shop& s);

};
ostream& operator<<(ostream& out, const Shop& s)//流提取
{
	cout << s._name << " " << s._price << " " << s._evaluate << endl;
	return out;
}

int main()
{
	vector<Shop> v = { { "苹果", 12.2, 5 }, { "香蕉", 3.3, 4 }, { "橙子", 6.6,
   3 }, { "菠萝", 1.5, 4 } };

	//sort(v.begin(), v.end(), ComparePriceLess());
	sort(v.begin(), v.end(), 
	[](const Shop& gl,const Shop& gr)->bool {return gl._price < gr._price; });

	//打印
	for (auto num : v)
	{
		cout << num;
	}
	cout << endl;

	//sort(v.begin(), v.end(), ComparePriceGreater());
	sort(v.begin(), v.end(), 
	[](const Shop& gl, const Shop& gr)->bool {return gl._price > gr._price; });

	//打印
	for (auto num : v)
	{
		cout << num;
	}
	cout << endl;
}

        运行结果:

        从结果可以发现,用lambda表达式可以完美的替代类调用仿函数,并且在代码量上也得到了显著的减少。

2.1 用lambda构建lambda变量

        以上虽然是lambda函数的用法之一,但是lambda函数习惯先给到一个变量,然后再用该变量去调用lambda函数,因为这样写可以提高代码的可读性。

        示例如下:

#define _CRT_SECURE_NO_WARNINGS 1

#include<iostream>
using namespace std;

int main()
{
	//构建lambda对象add
	//auto add = [](int x, int y)->int {return x + y; };
	auto add = [](int x, int y) {return x + y; };//省略返回值的写法

	int sum = add(10, 20);//用lambda对象add去调用lambda函数
	cout << sum << endl;

	//若直接用lambda表达式调用则可读性不高
	cout << [](int x, int y) {return x + y; }(13, 13) << endl;

	return 0;
}

        运行结果:

3、lambda表达式的类型

        lambda构建的变量虽然看起来都是lambda类型,但是他们相互之间不能够直接赋值,因为在底层,每个lambda构建的变量的类型都存在细微的差异。

        示例代码如下:

#define _CRT_SECURE_NO_WARNINGS 1

#include<iostream>
using namespace std;

int main()
{
	auto st1 = [] {cout << "hello world1" << endl; };
	auto st2 = [] {cout << "hello world2" << endl;};

	//st1 = st2;//lambda对象之间不能够相互赋值

	auto st3(st1);//但是可以拷贝构造一个新的lambda变量
	st3();

	//lambda可以赋值返回值类型相同的函数指针
	void(*pf)();
	pf = st2;
	pf();
	return 0;
}

         运行结果:

4、捕捉列表说明 

        如下图所示,虽然lambda表达式在main函数中,但是lambda表达式的函数体中不能直接用main函数的变量:

4.1 传值捕捉 

        捕捉列表可以捕捉父类作用域里的变量(也就是上述的main作用域的变量),并且可以在lambda表达式中用到捕捉的变量,写法如下:

#define _CRT_SECURE_NO_WARNINGS 1

#include<iostream>
using namespace std;

int main()
{
	int x = 1, y = 2;
	auto swap = [x, y]//此处省去了括号()
	{
		cout << x << " " << y << endl;
	};
	swap();
	return 0;
}

        运行结果:

        默认写法的捕捉方式均为传值捕捉,传值捕捉的写法还可以用一个‘=’号来表示,即以传值方式捕捉外部父作用域的所有变量,代码如下:

#define _CRT_SECURE_NO_WARNINGS 1

#include<iostream>
using namespace std;

int main()
{
	int x = 1, y = 2;
	auto swap = [=]//'='号表示以传值方式捕捉外部所有变量
	{
		cout << x << " " << y << endl;
	};
	swap();
	return 0;
}

        以上的传值捕捉,即对x和y的改变不会影响main函数中的x和y,但是我们发现此时不能直接对捕捉的x和y进行修改:

        因为lambda的捕捉列表中的变量都是默认被const修饰的,因此lambda函数内部是不能修改[capture-list]中的参数,这时候要用关键字mutable才可以对捕捉数据进行修改。 

4.2 mutable 

         mutable的作用是消除捕捉列表中的常属性,具体写法如下:

#define _CRT_SECURE_NO_WARNINGS 1

#include<iostream>
using namespace std;

int main()
{
	int x = 1, y = 2;
	auto swap = [=]()mutable//mutable
	{
		x++;
		y++;
		cout << x << " " << y << endl;
	};
	swap();
	cout << x << " " << y << endl;
	return 0;
}

        运行结果:

        而且从上面代码中可以发现,之前都省略了括号‘()’,但是如果用到了mutable关键字后,即使参数列表中没有参数也不能省略括号‘()’。

        并且从运行结果可以发现,传值捕捉是无法更改外部x和y的值,若想更改外部的x和y需用传引用捕捉。

4.3 传引用捕捉 

        传引用捕捉的符号为:‘&’,他也有两层用法,一是直接在捕捉列表中写&,表示以传引用的形式捕捉父作用域所有变量,二是对要捕捉的变量前面加上&。

        具体示例代码如下:

#define _CRT_SECURE_NO_WARNINGS 1

#include<iostream>
using namespace std;

int main()
{
	int x = 1, y = 2;
	cout << x << " " << y << endl;
	//auto swap = [&x, &y]
	auto swap = [&]
	{
		int temp = x;
		x = y;
		y = temp;
	};
	swap();
		cout << x << " " << y << endl;
	return 0;
}

        运行结果:

        从结果可以发现,lambda内部对x和y进行修改会影响外部的x和y(并且传引用捕捉不需要mutable也能改变捕捉变量的值)。 

        捕捉列表总结:

        1、[var]:表示传值方式捕捉变量 var
        2、[=]:表示传值方式捕获所有父作用域中的变量( 包括 this指针)
        3、[&var]:表示传引用方式捕捉变量 var
        4、[&]:表示传引用方式捕捉所有父作用域中的变量( 包括 this指针)

4.4 混合捕捉 

        传值捕捉和传引用捕捉两种写法可以相互交错使用,把这样的使用方式叫做混合捕捉,比如以下代码:

#define _CRT_SECURE_NO_WARNINGS 1

#include<iostream>
using namespace std;

int main()
{
	int x = 1, y = 2;
	cout << x << " " << y << endl;
	auto swap = [&,y]()mutable//除了y是传值捕捉,其他都是传引用捕捉
	{
		x++;
		y++;
	};
	swap();
		cout << x << " " << y << endl;
	return 0;
}

         运行结果:

        可以从结果看到,x是传引用捕捉,因此外面x的值发生了变化,而y是传值捕捉,则修改内部的x不会影响外部的y。 

5、lambda的大小

        因为底层还是会把lambda表达式当成一个仿函数的类去处理,所以lambda表达式中的参数列表会作为类中operator=()运算符重载的参数列表,lambda的函数体对应operator=()的函数体,而捕捉列表就对应的是类的成员。

        当捕捉列表什么都没有捕捉的时候,lambda的大小为1(表示对象的占位),示例代码如下:

#define _CRT_SECURE_NO_WARNINGS 1

#include<iostream>
using namespace std;

int main()
{
	int x = 1, y = 2;
	auto swap = [](int x,int y)mutable
	{
		int temp = x;
	};
	cout << sizeof(swap) << endl;
	return 0;
}

         运行结果:


        当lambda的捕捉列表中有捕捉的数据,则对标仿函数的类中含有成员变量的情况, 代码如下:

#define _CRT_SECURE_NO_WARNINGS 1

#include<iostream>
using namespace std;

int main()
{
	int x = 1, y = 2;
	auto swap = [y](int x,int y)mutable//捕捉了y
	{
		int temp = x;
	};
	cout << sizeof(swap) << endl;
	return 0;
}

        运行结果:

结语 

         以上就是关于lambda表达式的讲解,lambda实际上是为了避免程序员写仿函数时需要写大量的类而提出的一个新语法,本来让程序员实现的仿函数的类交给由编译器去完成,减轻了程序员的工作。

        最后希望本文可以给你带来更多的收获,如果本文对你起到了帮助,希望可以动动小指头帮忙点赞👍+关注😎+收藏👌!如果有遗漏或者有误的地方欢迎大家在评论区补充,谢谢大家!! 

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

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

相关文章

基于springboot+vue实现早餐店点餐系统项目【项目源码+论文说明】计算机毕业设计

基于springbootvue实现早餐店点餐系统演示 摘要 多姿多彩的世界带来了美好的生活&#xff0c;行业的发展也是形形色色的离不开技术的发展。作为时代进步的发展方面&#xff0c;信息技术至始至终都是成就行业发展的重要秘密。不论何种行业&#xff0c;大到国家、企业&#xff0…

基于51单片机的直流电机调速系统设计

基于51单片机的直流电机调速系统设计[proteus仿真] 电机调速系统这个题目算是课程设计和毕业设计中常见的题目了&#xff0c;本期是一个基于51单片机的直流电机调速系统设计 需要的源文件和程序的小伙伴可以关注公众号【阿目分享嵌入式】&#xff0c;赞赏任意文章 2&#xff…

【Web】浅聊Java反序列化之Rome——EqualsBeanObjectBean

目录 简介 原理分析 ToStringBean EqualsBean ObjectBean EXP ①EqualsBean直球纯享版 ②EqualsBean配合ObjectBean优化版 ③纯ObjectBean实现版 关于《浅聊Java反序列化》系列&#xff0c;纯是记录自己的学习历程&#xff0c;宥于本人水平有限&#xff0c;内容很水&a…

AI相关的实用工具分享

AI实用工具大赏&#xff1a;赋能科研与生活&#xff0c;探索AI的无限可能 前言 在数字化浪潮汹涌而至的今天&#xff0c;人工智能&#xff08;AI&#xff09;已经渗透到我们生活的方方面面&#xff0c;无论是工作还是生活&#xff0c;都在悄然发生改变。AI的崛起不仅为我们带…

搭建Android Studio开发环境

一、JDK 1、下载 2、安装 双击进行安装&#xff0c;修改安装路径为&#xff1a;D:\Java\jdk-17.0.4.1即可&#xff0c;安装完成后目录如下&#xff1a; 配置环境变量 3、测试 WinR&#xff0c;输入cmd&#xff0c;按Enter后&#xff0c;键入&#xff1a;java --version&…

云上攻防-云产品篇堡垒机场景JumpServer绿盟SASTeleport麒麟齐治

知识点 1、云产品-堡垒机-产品介绍&攻击事件 2、云产品-堡垒机-安全漏洞&影响产品 章节点&#xff1a; 云场景攻防&#xff1a;公有云&#xff0c;私有云&#xff0c;混合云&#xff0c;虚拟化集群&#xff0c;云桌面等 云厂商攻防&#xff1a;阿里云&#xff0c;腾讯…

力扣难题:重排链表

首先通过快慢指针找到中间节点&#xff0c;然后将中间节点之后和之前的部分分为两个链表&#xff0c;然后翻转后面的链表&#xff0c;注意方法&#xff0c;然后将两个链表交替链接。 /*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode…

【数理统计实验(三)】假设检验的R实现

&#x1f349;CSDN小墨&晓末:https://blog.csdn.net/jd1813346972 个人介绍: 研一&#xff5c;统计学&#xff5c;干货分享          擅长Python、Matlab、R等主流编程软件          累计十余项国家级比赛奖项&#xff0c;参与研究经费10w、40w级横向 文…

uglityjs非集成方式混淆js代码

文章目录 uglityjs非集成方式混淆js代码一、前言1.简介2.环境3.bat和ps1.ps1 文件.bat 文件 二、正文1.安装Node.js2.安装UglityJS3.代码混淆1&#xff09;单个文件2&#xff09;多个文件 uglityjs非集成方式混淆js代码 一、前言 1.简介 UglifyJS 是一个 JavaScript 解析器、…

3.10复试专业课日报【周末总结】

数据结构 考点一&#xff0c;考点二 操作系统 计算机网络 组成原理 1.什么是中断向量 2. 数据库 选择题80-100 1.数据库的逻辑模型&#xff08;数据模型&#xff09; 2.DCL,DML,DQL,DDL 3.数据库特点 算法 1.复习 对称二叉树&#xff0c;二叉树最大深度 2.只出现一…

计算机考研|保姆级择校+资料+全年规划

本科211&#xff0c;研究生上岸某985 计算机考研备考过程中走了不少弯路&#xff0c;希望我的经验能够帮助大家少走弯路 大家决定考研之前&#xff0c;一定要认真思考自己考研的目的是什么&#xff0c;有的人是随大流&#xff0c;别人考研&#xff0c;就跟风考研&#xff0c;有…

vulhub中Weblogic WLS Core Components 反序列化命令执行漏洞复现(CVE-2018-2628)

Oracle 2018年4月补丁中&#xff0c;修复了Weblogic Server WLS Core Components中出现的一个反序列化漏洞&#xff08;CVE-2018-2628&#xff09;&#xff0c;该漏洞通过t3协议触发&#xff0c;可导致未授权的用户在远程服务器执行任意命令。 访问http://your-ip:7001/consol…

初识REDHAWK

文章目录 前言一、什么是 REDHAWK?1、概述2、REDHAWK 的应用 二、REDHAWK 的流程管理和交互方法1、流程管理2、数据传输 三、入门1、安装 REDHAWK2、IDE 快速入门①、启动 REDHAWK IDE②、打开 Chalkboard③、创建信号发生器④、测试组件的输入/输出响应 前言 REDHAWK 是一个…

跨平台是什么意思?——跟老吕学Python编程

跨平台是什么意思&#xff1f;——跟老吕学Python编程 跨平台跨平台释义跨平台软件数据库管理系统(DBMS)&#xff1a;网站服务器、应用程序服务器&#xff1a;网络浏览器&#xff1a; 跨平台编程语言跨平台详细解说跨平台应用前景 跨平台 计算机领域术语 跨平台概念是软件开发中…

Python 强大邮件处理库 Imbox

目录 IMAP Mailbox Imbox 安装 特性 提取邮件内容 处理附件 安全性 示例 1&#xff1a;读取收件箱中的邮件 2&#xff1a;搜索并下载附件 3&#xff1a;连接到IMAP服务器获取所有邮件 结论 IMAP Mailbox IMAP&#xff08;Internet Message Access Protocol&#x…

Ps:清理

清理 Purge命令位于“编辑”菜单下&#xff0c;它主要用于释放 Photoshop 使用的内存资源&#xff0c;有助于提高系统的性能。 通过使用“清理”命令&#xff0c;用户可以有效管理 Photoshop 的资源使用&#xff0c;特别是在处理大型文件或进行长时间编辑会话时。 定期清理可以…

什么是GoogLeNet,亮点是什么,为什么是这个结构?

GooLeNet 亮点 最明显的亮点就是引入了Inception&#xff0c;初衷是多卷积核增加特征的多样性&#xff0c;提高泛化能力 &#xff0c;比如&#xff0c;最下边是一个输入层&#xff0c;然后这个输入分别传递给1*1&#xff0c;3 * 3 &#xff0c;5 * 5和一个最大池化层&#xff…

盘点5个正规靠谱的赚钱平台,有手机或电脑就可以增收

找到一个真正靠谱的赚钱平台是一个不错的起点。接下来的一些建议&#xff0c;都是为了让你能在互联网的宇宙世界中&#xff0c;平稳地走出创收的第一步。 1&#xff0c;自媒体写文章 写文章是一项非常适合文学爱好者的兼职工作。如果你拥有良好的文学功底和写作技巧&#xff…

智慧公厕_智慧化公厕_智慧的公厕_公厕智慧化_智能智慧公厕_智慧化的公厕

在当代城市发展中&#xff0c;智慧公厕作为公共厕所信息化的主要表现形式&#xff0c;正在以惊人的速度推动着城市公共环境卫生的智慧化进程。作为智慧城市体系的重要组成部分&#xff0c;智慧公厕不仅提供方便、卫生的公共厕所服务&#xff0c;还提升了城市整体形象&#xff0…

人民网(人民号)如何发布文章新闻,人民网怎么投稿,附人民日报价格多少钱

最近有很多朋友问到一个问题&#xff0c;就是人民网如何发布文章新闻&#xff0c;以及人民网怎么投稿。作为一个专业的媒体发稿平台&#xff0c;媒介多多网为大家提供了一个非常好的解决方案。 首先&#xff0c;人民网作为我国权威媒体之一&#xff0c;其新闻发布渠道非常严谨…