C++11 lambda+包装器+可变参数模板

news2024/11/24 17:05:37

索引

  • lambda表达式
      • (1).什么是lambda
      • (2).lambda基本规则
      • (3).lambda实现原理
  • 包装器
  • 可变参数模板

lambda表达式

(1).什么是lambda

假设有这样一个类

struct Goods
{
string _name;  // 名字
double _price; // 价格
int _evaluate; // 评价
}

现在要将商品分别按照名字,价格三种方式排序,为此我们必须写三个仿函数,但这个有点麻烦,因为一旦比较的逻辑不一样,就得多实现一个类,所以c++11出现了与局部深度绑定的lambda表达式,其本质上是一个匿名函数。
eg:

vector<Goods> v = { { "苹果", 2.1, 5 }, { "香蕉", 3, 4 }, { "橙子", 2.2,
3 }, { "菠萝", 1.5, 4 } };
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; });

(2).lambda基本规则

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

[capture-list] :捕捉列表,该列表总是出现在lambda函数的开始位置,编译器根据[]来判断接下来的代码是否为lambda函数,捕捉列表能够捕捉上下文的变量供lambda函数使用
(parameters):参数列表,与普通函数的参数列表一致,如果不需要传参,则可以与()一起省略
mutable:默认情况下,lambda函数总是一个const函数,即捕捉过来的参数自动加了const,如果需要改变参数const’属性,需在()后加mutable
->returntype:返回值类型,用追踪返回类型形式声明函数的返回值类型,没有返回值时此部分可省略,返回值类型明确情况下,也可省略,由编译器对返回类型进行推导。
{statement}:函数体。除可以使用参数外,还可以使用所有捕获到的变量
小结:参数和返回值可以省略,捕捉列表和函数体不能省略。

[capture-list] (parameters) mutable -> return-type { statement }
    	 捕捉列表  参数  返回值  函数体
	最简单的lambda表达式,该表达式无意义
	[] {};
	auto Add1 = [](int x, int y)->double {return (x + y) / 3.0; };
	cout << Add1(2, 3) << endl;//Add1其实就是一个局部匿名函数
	int x = 3;

	int a = 4, b = 5;
	auto Add2 = [a, b,x] ()mutable//无参数可以直接省略
	{
		a = a + 3;
		b = b + 3;//加了mutable只能在函数体内部改变值,但是出了作用域还是无法改变的
		return a + b+x;
	};
	cout << Add2() << endl;
	cout << a << " " << b << endl;//4 5
	auto Swap = [](int& x, int& y)
	{
		int tmp = x;
		x = y;
		y = tmp;
	};
	Swap(a, b);
	cout << a << " " << b << endl;//5  4
	通过上述的例子可以看出,lambda表达式实际上可以理解成一个匿名函数
	该函数无法直接调用,若想直接调用,可借助auto将其赋值给一个变量
	
	捕捉列表描述了上下文哪些数据可以被lambda使用,以及使用的方式是传值还是传引用

	/*  [var]:表示值传递方式捕捉变量var
		[=]:表示值传递方式捕获所有父作用域中的变量(包括this)
		[&var]:表示引用传递捕捉变量var
		[&]:表示引用传递捕捉所有父作用域中的变量(包括this)
		[this]:表示值传递方式捕捉当前的this指针*/
	
	/*a.父作用域指包含lambda函数的语句块 即{}中的语句块
		b.语法上捕捉列表可由多个捕捉项组成,并以逗号分割。
		比如:[=, &a, &b]:以引用传递的方式捕捉变量a和b,值传递方式捕捉其他所有变量
		[&,a, this]:值传递方式捕捉变量a和this,引用方式捕捉其他变量
		c.捕捉列表不允许变量重复传递,否则就会导致编译错误。
		比如:[=, a]: = 已经以值传递方式捕捉了所有变量,捕捉a重复*/
	捕捉列表只能捕捉局部变量,不能捕捉全局变量
	int c = 100, d = 200;
	static int g = 20;
	auto Addn = [c, d,20] {return c + d; };//此时20是静态变量 不能捕捉
	cout << Addn() << endl;
	auto Swap2 = [&c, &d](int x, int y) {c = 2; d = 3; return c + d + x + y; };//引用捕捉
	 此时并不是传地址而是传引用
	auto Swap2 = [&](int x, int y) {c = 2; d = 3; return c + d + x + y; };//引用捕捉与上述作用一样,捕捉变量都是引用传递
	auto Swap2 = [=](int x, int y) {c = 2; d = 3; return c + d + x + y; };//报错,值传递,此时不加mutabl,捕捉的变量具有const
	auto Swap2 = [=](int x, int y) mutable{c = 2; d = 3; return c + d + x + y; };
	报错,值传递,此时不加mutabl,捕捉的变量具有const
	但此时无法修改c 和d的值
	int t = 500;
	auto Swap2 = [=, &c](int x, int y) mutable {c = 2; d = 3; t = 1000; return c + d +t+ x + y; };
	=表示捕捉的都是值传递,但是c是引用传递
	此时在函数体内部用的是修改后的值
	但因为是值传递,此时只能成功修改c的值,d和t在函数体中修改的都是其临时拷贝

总结: lambda就是定义了一个匿名的可调用的对象,一般定义在局部,特点是跟普通变量相比可以深度绑定局部的数据,比如说参数很多可以直接捕捉,不用传参了,有一些便捷性。
所以lambda可以提到仿函数吗?
不行,仿函数既可以传类型也可以传对象,但是lambda整体是一个对象,他只能用于那些传递对象的场景,eg:sort用lambda非常好,因为sort传的就是对象,但是在模板参数的时候lambda可能就不怎么好用。

(3).lambda实现原理

先补充一个lambda的规则:lambda表达式之间不能相互赋值,即使看起来类型相同
eg:

auto f1 = []{cout << "hello world" << endl; };
auto f2 = []{cout << "hello world" << endl; };
f1 = f2 会编译失败
void(*PF)()
但是可以将lambda表达式赋值给相同类型的指针
PF = f1;
但是不建议这样做

在这里插入图片描述

UUID 是 通用唯一识别码(Universally Unique Identifier)的缩写,是一种软件建构的标准,亦为开放软件基金会组织在分布式计算环境领域的一部分。其目的,是让分布式系统中的所有元素,都能有唯一的辨识信息,而不需要通过中央控制端来做辨识信息的指定。如此一来,每个人都可以创建不与其它人冲突的UUID。在这样的情况下,就不需考虑数据库创建时的名称重复问题。最广泛应用的UUID,是微软公司的全局唯一标识符(GUID),而其他重要的应用,则有Linux ext2/ext3文件系统、LUKS加密分区、GNOME、KDE、Mac OS X等等。另外我们也可以在e2fsprogs包中的UUID库找到实现。

所以上述的即使f1与f2表面上看上去函数是一样的,但是在其所生成的仿函数名称确实完全不一样的,所以不能赋值。

包装器

function包装器也叫做适配器。c++中的function本质是一个类模板,也是一个包装器,为什么需要它?
eg:ret = func(x)
上面的func可能是什么?
func可能是函数名?函数指针?函数对象(仿函数对象)?也有可能是lambda表达式对象?这些都是可调用的类型,所以如此丰富的类型可能也会导致模板效率降低。
eg:

template<class F, class T>
T useF(F f, T x)
{
static int count = 0;
cout << "count:" << ++count << endl;
cout << "count:" << &count << endl;
return f(x);
}
double f(double i)
{
return i / 2;
}
struct Functor
{
double operator()(double d)
{
return d / 3;
}
};
int main()
{
通过上面的程序验证,我们会发现useF函数模板实例化了三份。
包装器可以很好的解决上面的问题
// 函数名
cout << useF(f, 11.11) << endl;
// 函数对象
cout << useF(Functor(), 11.11) << endl;
// lamber表达式
cout << useF([](double d)->double{ return d/4; }, 11.11) << endl;
return 0;
}

在这里插入图片描述模板参数说明:
Ret: 被调用函数的返回类型
Args…:被调用函数的形参
使用方法如下:

	function<int(int, int)>func1 = f;
	cout << func1(1, 2) << endl;
	function<int(int, int)>func2 = Functor();
	cout << func2(2, 4) << endl;
	//静态成员函数的包装跟其他的包装一样
	function<int(int, int)>func3 = &Plus::plusi;//取地址符号可加可不加,但最好加上
	cout << func2(5, 4) << endl;
	//非静态成员函数有点区别
	function<double(Plus, double, double)>func4 = &Plus::plusd;
	cout << func4(Plus(), 5.2, 3.5) << endl;
	//Plus()匿名对象,因为非静态成员函数要用this指针去调用
	//静态成员函数不用,上述需要靠匿名对象调用函数
	function<int(int, int)>func5 = [](int a, int b) {return a + b; };
	cout << func5(100, 200) << endl;

可以看到包装器统一的特点是统一类型
c++中常用命令对应函数

map<string,function>
命令对应函数
eg
cout << opFuncMap["普通函数指针"](1, 2) << endl;
	cout << opFuncMap["函数对象"](1, 2) << endl;
	

在这里插入图片描述
所以可以像下面这样

int f(int a, int b)
{
	return a - b;
}

struct Functor
{
public:
	int operator() (int a, int b)
	{
		return a + b;
	}
};


class Plus
{
public:
	Plus(int x = 2)
		:_x(x)
	{}

	int plusi(int a, int b)
	{
		return (a + b) * _x;
	}
private:
	int _x;
};
void Teste()
{
	map<string, std::function<int(int, int)>> opFuncMap =
	{
		{ "普通函数指针", f },
		{ "函数对象", Functor() },
		{ "成员函数指针", std::bind(&Plus::plusi, Plus(10), placeholders::_1, placeholders::_2) }
	};

	cout << opFuncMap["普通函数指针"](1, 2) << endl;
	cout << opFuncMap["函数对象"](1, 2) << endl;
	cout << opFuncMap["成员函数指针"](1, 2) << endl;
}

可变参数模板

c++98/03,类模板和函数模板中只能包含固定数量的模板参数,c++11新特性可以接受可变参数的函数模板和类模板,使用起来稍微一点技巧。

//Argss是一个模板参数包,args是一个函数形参参数包
//声明一个参数包Args...args,这个参数包中包含0到任意个模板参数
template<class ...Args>
void ShowList1(Args... args){}

上面的参数args前面有省略号,所以它就是一个可变模板参数,我们把带省略号的参数称为“参数包”,它里面包含了0到N(N>=0)个模板参数,我们无法直接获取参数包args中的每个参数,只能通过展开参数包的方式来获取参数包重点每个参数,这是使用可变模板参数的一个主要特点,也是最大的难点,下面我用一张图来演示如果展开。
在这里插入图片描述
可变参数在STL中的运用
在这里插入图片描述
首先看到emplace_back系列的接口,支持模板的可变参数,且是万能引用。

list<pair<string, int>>li;
	li.push_back(make_pair("zjt", 20));
	li.emplace_back("nidie", 18);

emplace_back支持可变参数,拿到pair对象参数后自己去创建对象,
在这看到除了用法上面,和push_back没有太大区别。
在这里插入图片描述

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

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

相关文章

“健康中国”战略下如何推进公共卫生建设,海尔生物医疗给出“智慧答案”

【潮汐商业评论/原创】 公共卫生是一个老话题&#xff0c;但在新时代的背景下正在呈现出诸多新故事。在人民健康需求日益提升的当下&#xff0c;推动公共卫生服务体系的高效、便捷升级成了新时期的一大命题&#xff0c;而这一问题的答案则指向了公共卫生需要“数智化”。 在此…

Python之第十章 IO及对象列化

目录 Python之第十章 IO及对象列化 1.IO流&#xff08;IO stream&#xff09; 1.概述 2.IO流定义 3.流的分类 2.open方法 1.过程 2.缓冲区&#xff08;buffer&#xff09; 使用缓存区的必要性&#xff1a; 缓冲区分类&#xff1a; 3.格式 4.b模式 5.模式 6.文件对…

CentOS 7搭建LittlePaimon原神机器人

CentOS 7.6搭建LittlePaimon原神机器人 前言 最近小伙伴说别人的QQ群里有个原神的机器人&#xff0c;可以随时查询自己账号的角色卡信息。然后我自己查了下资料&#xff0c;发现不是很难弄&#xff0c;所以帮忙也弄了一个。 目前使用较多的原神机器人&#xff1a; LittlePaim…

SpringMVC学习篇(八)

SpringMVC拦截器 1.拦截器和过滤器的区别 过滤器拦截器servlet规范中(java ee)规范中的一部分,任何java web工程都可以使用拦截器是框架提供的,如只有在SpringMVC框架下的工程才能使用其提供的拦截器在url-pattern中配置了/*之后,可以拦截任何一切资源拦截器只会拦截控制器方…

easyrecovery工具2023最新版一键恢复丢失数据免费下载

通常&#xff0c;许多人会将工作或生活中的数据存储在我们的计算机上。很多时候&#xff0c;由于我们的误操作或其他一些问题&#xff0c;很容易错误地删除一些文件和数据。特别是&#xff0c;一些计算机故障总是会导致数据丢失&#xff0c;这是非常麻烦的。当需要重新安装系统…

JS 对象总结

对象 创建对象 有两种方式&#xff1a; 通过 new 操作符实例化一个对象&#xff0c;再添加属性。 let person new Object(); person.name "孤城浪人"; person.sayName function() { console.log(this.name); };构造函数&#xff0c;若不需要传参&#xff0…

代码随想录——单词接龙(图论)

题目 字典 wordList 中从单词 beginWord 和 endWord 的 转换序列 是一个按下述规格形成的序列&#xff1a; 序列中第一个单词是 beginWord 。 序列中最后一个单词是 endWord 。 每次转换只能改变一个字母。 转换过程中的中间单词必须是字典 wordList 中的单词。 给你两个单词 b…

AWVS的简介与安装

目录预备知识实验目的实验环境实验步骤一任务描述&#xff1a;AWVS的简介实验步骤二任务描述&#xff1a;进行AWVS10.5的安装、界面介绍和简单的使用实验步骤三任务描述&#xff1a;AWVS 11.x的安装与简单使用预备知识 Acunetix Web Vulnerability Scanner&#xff08;简称AWV…

Qtcreator中文显示乱码问题终于解决

问题描述&#xff1a;Qtcreator安装好后打印中文在控制台输出乱码&#xff08;自己也在网上查找了好久&#xff0c;终于找到解决方法了&#xff09;。 原因剖析&#xff1a;因为项目的编码与控制台的编码不一致导致的&#xff0c;而qt编码设置里并没有控制台的默认编码&#xf…

华为M-LAG跨设备链路聚合技术理论讲解

目录 为什么会出现M-LAG M-LAG基本概念 M-LAG建立过程 M-LAG的协议兼容性 M-LAG的防环机制 M-LAG正常工作流量转发 单播流量转发 组播流量转发 广播流量转发 M-LAG故障场景流量转发 上行链路故障 下行链路故障 M-LAG主设备故障 Peer-link故障 M-LAG二次故障&…

Kafka部署实验

一、实验介绍 1.1实验内容 实验在Hadoop集群上部署Kafka分布式发布订阅消息系统&#xff0c;并完成kafka消息管理验证。 1.2实验知识点 Kafka集群部署 Kafka消息处理流程 1.3实验环境 Kafka2.11 网易云平台 1.4实验资源 资源名称存储目录Kafka安装包/opt/software/pack…

工业数采网关 工业数采模块 工业数采工业数采终端硬件

计讯物联TG462工业数据采集网关&#xff0c;支持工业采集、边缘计算、无线通信、远程控制、远程运维&#xff0c;广泛应用于智慧工业远距离通信自动化管控物联网场景。计讯工业数采网关TG462接口丰富、丰富协议库、支持主流PLC&#xff0c;对接第三方云平台&#xff0c;工业级设…

【软件测试面试题】面试官:你在工作中发现最有意义的bug?让他满意的回答......

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

iOS开发之自定义的framework添加第三方framework,lipo和ar命令看.o文件

由于需要将之前生成的mediapipe.framework添加到自己的framework中&#xff0c;但是很奇怪用普通的拖拽方式添加&#xff0c;项目工程在加载运行自己的framework时&#xff0c;总是找不到mediapipe.framework中的头文件&#xff0c;而只编译自己的framework时&#xff0c;也是可…

免费域名证书最新申请方式大全

目前市场环境下&#xff0c;可获得域名SSL证书的方式有很多&#xff0c;一般有付费和免费划分。对于想免费使用域名SSL证书的朋友&#xff0c;这里收集整理了几个常用的SSL证书申请方式。 对于SSL证书的用处&#xff0c;简单的来说&#xff0c;就是加密数据传输&#xff0c;使…

这么讲不怕你不懂负载均衡

现在前沿技术领域一个很有突破口和争议性的领域就是分布式系统以及高并发的解决与处理。而解决高并发其中一个很有意思的方法就是负载均衡。 那么&#xff0c;究竟什么才是负载均衡呢&#xff1f; 首先&#xff0c;维基百科是这样说的&#xff1a; 负载平衡&#xff08;英语&a…

Java_多态

作者&#xff1a;爱塔居的博客_CSDN博客-JavaSE领域博主 专栏&#xff1a;JavaSE 作者简介&#xff1a;大三学生&#xff0c;希望跟大家一起进步 文章目录 目录 文章目录 一、多态概念 二、多态实现条件 三、重写 四、向上转型和向下转型 4.1 向上转型 4.2 向下转型 五、多态的…

社交电商平台的消费返利模式——共享购

实际上目前很多商家平台提到做电商平台&#xff0c;坚信最先第一个想到的是一些大型好像淘宝、某猫、某多多这些&#xff0c;但是随着社交媒体电商行业发展&#xff0c;大量商业运营模式及其商业平台&#xff0c;第一个的自然也就相对于交易返利模式的渠道&#xff0c;那大家在…

ubuntu中redis客户端与服务端命令、redis数据类型、字符串string、哈希hash、列表list、集合set、有序集合zset操作命令

一、NoSQL概述 NoSQL(not only SQL)&#xff1a;泛指非关系型数据库&#xff0c;是一类新出现的数据库&#xff0c;不支持SQL语法&#xff0c;其存储的数据都是kv形式&#xff0c;存储结构与关系型数据库中的关系表完全不同 NoSQL产品种类&#xff1a;主要有Redis、MongoDB、…

超百万人用它生成3D头像,这项技术刚刚中选了SIGGRAPH Asia 2022

如何才能做一个和真人一样的 3D 头像&#xff1f; 先上传一张照片&#xff1a; 变成这样&#xff1a; 换一个人的照片&#xff1a; 再看一个例子&#xff1a; 眼镜也可以放进来&#xff1a; 在此基础上&#xff0c;还可以换上各种各样的发型、饰品&#xff0c;眼睛、帽子、发色…