C++11新特性(下)

news2024/9/30 17:25:40

在这里插入图片描述

文章目录

  • 1. 可变参数模板
    • 1.1 empalce相关接口函数
  • 2. lambda表达式
    • 2.1 C++98中的一个例子
    • 2.2 lambda表达式语法
    • 2.3 函数对象与lambda表达式
  • 3. 包装器
    • 3.1 function包装器
    • 3.2 bind

1. 可变参数模板

C++11的新特性可变参数模板能够让您创建可以接受可变参数的函数模板和类模板。相比C++98,类模版和函数模版中只能含固定数量的模版参数,可变模版参数无疑是一个巨大的改进。

下面就是一个基本可变参数的函数模板
在这里插入图片描述
上面的参数args前面有省略号,所以它就是一个可变模版参数,我们把带省略号的参数称为“参数包”,它里面包含了0到N(N>=0)个模版参数。
在这里插入图片描述
这里可以打印参数包里面的参数个数,但是用法有点奇怪。

这时候,有的人想获取参数包里的每个参数,但是语法不支持使用args[i]这样方式获取可变参数,只能通过展开参数包的方式来获取参数包中的每个参数。

方法一:递归函数方式展开参数包
在这里插入图片描述
首先,我们传的1,‘x’,1.1。1传给了val,'x’和1.1传给了args。所以第一次打印参数个数是2,然后打印val是1,类型是int。然后递归自己,这样’x’传给了val,1.1传给了args。当参数包里只剩下一个值后,再去调用自己,会传给最匹配自己的,然后打印完成后结束。如果没有我们自己写的那个,那么args为0时,还会递归自己就会报错。

另外一种写法:
在这里插入图片描述
这里也是同样的道理。

方法二:逗号表达式展开参数包
在这里插入图片描述
我们知道逗号表达式会按顺序执行逗号前面的表达式,(printarg(args), 0),也是按照这个执行顺序,先执行printarg(args),再得到逗号表达式的结果0。
同时还用到了C++11的另外一个特性——初始化列表,通过初始化列表来初始化一个变长数组, {(printarg(args), 0)…}将会展开成((printarg(arg1),0),(printarg(arg2),0), (printarg(arg3),0), etc… ),最终会创建一个元素值都为0的数组。由于是逗号表达式,在创建数组的过程中会先执行逗号表达式前面的部分printarg(args)打印出参数,也就是说在构造int数组的过程中就将参数包展开了,这个数组的目的纯粹是为了在数组构造的过程展开参数包。

另外一种写法:
在这里插入图片描述

1.1 empalce相关接口函数

STL容器中的empalce相关接口函数:vector list

在这里插入图片描述
首先我们看到的emplace系列的接口,支持模板的可变参数,并且万能引用。那么emplace系列接口的优势到底在哪里呢?

答案是:emplace_back是直接构造了,push_back是先构造,再移动构造,其实差别并不是很大。

2. lambda表达式

2.1 C++98中的一个例子

在C++98中,如果想要对一个数据集合中的元素进行排序,可以使用std::sort方法。
在这里插入图片描述
如果待排序元素为自定义类型,需要用户定义排序时的比较规则。当我们每次去比较一个成员变量的时候,都要去写一个仿函数,这样就太复杂了,所以在C++11语法中出现了Lambda表达式。

2.2 lambda表达式语法

lambda表达式实际是一个匿名函数
lambda表达式书写格式:[capture-list] (parameters) mutable -> return-type { statement }

1. lambda表达式各部分说明
[capture-list] : 捕捉列表,该列表总是出现在lambda函数的开始位置,编译器根据[]来判断接下来的代码是否为lambda函数,捕捉列表能够捕捉上下文中的变量供lambda函数使用

(parameters):参数列表。与普通函数的参数列表一致,如果不需要参数传递,则可以连同()一起省略

mutable:默认情况下,lambda函数总是一个const函数,mutable可以取消其常量性。使用该修饰符时,参数列表不可省略(即使参数为空)

->returntype:返回值类型。用追踪返回类型形式声明函数的返回值类型,没有返回值时此部分可省略。返回值类型明确情况下,也可省略,由编译器对返回类型进行推导

{statement}:函数体。在该函数体内,除了可以使用其参数外,还可以使用所有捕获到的变量

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

举个例子:
在这里插入图片描述
通过上述例子可以看出,lambda表达式实际上可以理解为无名函数,该函数无法直接调用,如果想要直接调用,可借助auto将其赋值给一个变量。

mutable我们暂时先不说,如果我们想在lambda表达式里面使用a或者b的话,我们需要在捕捉列表里面捕捉。

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

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

注意:
1.父作用域指包含lambda函数的语句块

2.语法上捕捉列表可由多个捕捉项组成,并以逗号分割
比如:[=, &a, &b]:以引用传递的方式捕捉变量a和b,值传递方式捕捉其他所有变量。
[&,a, this]:值传递方式捕捉变量a和this,引用方式捕捉其他变量。

3.捕捉列表不允许变量重复传递,否则就会导致编译错误
比如:[=, a]:=已经以值传递方式捕捉了所有变量,捕捉a重复。

4.在块作用域以外的lambda函数捕捉列表必须为空

5.在块作用域中的lambda函数仅能捕捉父作用域中局部变量,捕捉任何非此作用域或者非局部变量都会导致编译报错。

6.lambda表达式之间不能相互赋值,即使看起来类型相同

举些例子:
在这里插入图片描述
这是一个交换函数,我们传值的话,只是改变了x和y,但是没有改变a和b,所以我们需要传引用。
在这里插入图片描述
在这里插入图片描述
如果我们在捕捉列表里面去捕捉a和b,然后交换会发生错误,因为lambda函数总是一个const函数,我们这里就需要mutable。
在这里插入图片描述
mutable只是让传值捕捉变量const属性去掉了,但还是传值。所以mutable并没有太大作用。我们还是要传引用。
在这里插入图片描述

学到这里,我们可以用lambda表达式来使用sort函数了。

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; });

那么以后是不是不用仿函数了呢
其实并不是,仿函数可以传对象或者类型(unordered_set/unordered_map),但是lambda是一个对象,它不能传类型。

2.3 函数对象与lambda表达式

函数对象,又称为仿函数,即可以想函数一样使用的对象,就是在类中重载了operator()运算符的类对象。
在这里插入图片描述
我么可以看到:lambda表达式的实现是相同的,也不能相互赋值。这是为什么呢?
在这里插入图片描述
我们看这个代码的反汇编:
在这里插入图片描述
我们可以看到lambda底层就是去调用了仿函数。每个lambda都会转换成一个仿函数类型,这个仿函数名称是lambda+uuid,这个uuid就是为了区别每个lambda所以,每个lambda都不相同,因此不能相互赋值。

lambda表达式的其它用法:
在这里插入图片描述
可以拷贝构造和赋值给一个函数指针。

3. 包装器

3.1 function包装器

function包装器 也叫作适配器。C++中的function本质是一个类模板,也是一个包装器

举个例子:
在这里插入图片描述
在这里插入图片描述
通过上面的程序验证,我们会发现useF函数模板实例化了三份(每个count的地址不一样),这样会导致模板的效率低下!包装器可以很好的解决上面的问题。

在这里插入图片描述

使用方法如下:
在这里插入图片描述
这是三个比较常见的包装方式。那么类里的成员函数也可以包装。
在这里插入图片描述
这是静态成员函数的包装,这里的&符号可加可不加。但是非静态成员函数就有区别了。
在这里插入图片描述
因为非静态成员函数有this,所以缺少参数,我们需要把this也封装一下。
在这里插入图片描述
但是非静态成员函数在封装的时候,我们不能把&去掉。

有了包装器,如何解决模板的效率低下,实例化多份的问题呢
在这里插入图片描述
这里,我们将函数指针,仿函数对象,lambda表达式都给变成包装器。
在这里插入图片描述
这样在实列化的时候就实例化成了一份。

3.2 bind

std::bind函数定义在< functional >头文件中,是一个函数模板,它就像一个函数包装器(适配器),接受一个可调用对象,生成一个新的可调用对象来“适应”原对象的参数列表。一般而言,我们用它可以把一个原本接收N个参数的函数fn,通过绑定一些参数,返回一个接收M个(M可以大于N,但这么做没什么意义)参数的新函数。同时,使用std::bind函数还可以实现参数顺序调整等操作。
在这里插入图片描述
可以将bind函数看作是一个通用的函数适配器,它接受一个可调用对象,生成一个新的可调用对象来“适应”原对象的参数列表。调用bind的一般形式:auto newCallable = bind(callable,arg_list);

其中,newCallable本身是一个可调用对象,arg_list是一个逗号分隔的参数列表,对应给定的callable的参数。当我们调用newCallable时,newCallable会调用callable,并传给它arg_list中的参数

arg_list中的参数可能包含形如_n的名字,其中n是一个整数,这些参数是“占位符”,表示newCallable的参数,它们占据了传递给newCallable的参数的“位置”。数值n表示生成的可调用对象中参数的位置:_1为newCallable的第一个参数,_2为第二个参数,以此类推。

使用举例:
在这里插入图片描述
我们可以看到,前面的两种包装都是传两个参数,第三个非静态成员变量是传三个参数。如果我们想让它也传两个参数,我们就需要绑定。
在这里插入图片描述
这里的第一个参数,原来是匿名对象,是缺省值2,现在我们给定10。这样只需要传两个参数就行了。那么我们也可以改成传一个参数。
在这里插入图片描述
_1 _2 _3… 表示你要自己传的那些参数,_1表示第一个参数传给_1。

那么我们也可以调整传递的顺序:
在这里插入图片描述
在func6里面,_2就是20,_1就是10,然后a就是20,b就是10。

那么bind的使用场景在哪里呢?
在这里插入图片描述
因为在第三个非静态成员变量传需要三个参数,而这里固定是两个。所以,我们需要绑定。
在这里插入图片描述

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

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

相关文章

Matlab与ROS---Action与Gazebo(六)

0. 简介 对于ROS1而言&#xff0c;其在Matlab当中相较于ROS2还有一些比较高级的用法&#xff0c;比如说我们接下来要说的Action和Gazebo仿真。 1. ROS Action ROS的Action行为模式当中也存在有一个客户端到服务器的通信关系。Action行为模式使用ROS主题将目标消息从客户机发…

【技巧】飞书多维表格零代码连接飞书多维表格,实现表单自动同步

飞书多维表格用户使用场景&#xff1a; 在公司日常工作中&#xff0c;各个部门使用飞书多维表格记录签订合同、文件审核、归档等事务&#xff0c;常需要行政人员辅助处理&#xff0c;将这些子表单的数据汇总到一个总表单中。但每个部门对应的事务较为复杂&#xff0c;子表单数量…

OpenCV例程赏析

OpenCV例程赏析 ①SITF特征检测匹配(目标查找)例程&#xff1a;…\opencv\sources\samples\python2\find_obj.py(asift.py) #!/usr/bin/env python ‘’’ Feature-based image matching sample. Note, that you will need the https://github.com/opencv/opencv_contrib r…

什么是内容交付网络?

内容交付网络&#xff08;CDN&#xff09;是一个全球分布的网络服务器或存在点&#xff08;PoP&#xff09;&#xff0c;其目的是提供更快的内容交付&#xff0c;内容被复制并存储在整个CDN中&#xff0c;因此用户可以访问存储在地理上离用户最近的位置的数据。这与仅在一个中央…

Flinkx/Datax/Flink-CDC 优劣势对比

Flinkx/Datax/Flink-CDC 优劣势对比_HiBoyljw的博客-CSDN博客 一、FlinkX简介 FlinkX是一款基于Flink的分布式离线/实时数据同步插件&#xff0c;可实现多种异构数据源高效的数据同步&#xff0c;其由袋鼠云于2016年初步研发完成&#xff0c;目前有稳定的研发团队持续维护&…

微前端解决方案

目录 微前端解决方案微前端的整体架构微前端部署平台 微前端解决方案 在理想的情况下&#xff0c;期望能达到&#xff0c;将一个复杂的单体应用以功能或业务需求垂直的切分成更小的子系统&#xff0c;并且能够达到以下能力&#xff1a; 子系统间的开发、发布从空间上完成隔离…

java学员学生综合测评管理系统

目 录 摘 要 I ABSTRACT II 第一章 绪论 1 1.1课题背景 1 1.2目的和意义 1 1.3开发工具及技术 2 1.3.1开发工具 2 1.3.2 JSP技术 2 1.4软硬件需求 3 第二章 系统分析 5 2.1可行性分析 5 2.1.1技术可行性 5 2.1.2经济可行性 5 2.1.3操…

GrassRouter多链路聚合通信系统保障公路网络稳定全面覆盖解决方案

近年来国内经济不断发展&#xff0c;城市道路交通能力迅速提高&#xff0c;各省市道路交通体系不断完善&#xff0c;促使高速公路运能得到极大提高&#xff0c;公路运输的通达性、舒适性得到明显提高。随着现代化高速公路的建设&#xff0c;新一代无线网络监控系统&#xff0c;…

Jmeter控制器 Logic Controller

控制器包含&#xff1a; 1.Loop Controller 作⽤&#xff1a;指定其⼦节点运⾏的次数&#xff0c;可以使⽤具体的数值&#xff0c;也可以使⽤变量    Forever选项&#xff1a;表示⼀直循环下去   如果同时设置了线程组的循环次数和循环控制器的循环次数&#xff0c;那循环…

大屏使用echart开发省市地图,并点击省获取市地图

1. 本文在基础上进行改进&#xff0c;后端使用若依后端 IofTV-Screen: &#x1f525;一个基于 vue、datav、Echart 框架的物联网可视化&#xff08;大屏展示&#xff09;模板&#xff0c;提供数据动态刷新渲染、屏幕适应、数据滚动配置&#xff0c;内部图表自由替换、Mixins注…

ZooKeeper的安装和配置过程

ZooKeeper的安装和配置过程 ZooKeeper服务器是用Java创建的&#xff0c;它需要在JVM上运行&#xff0c;所以需要使用JDK1.6及以上版本。 查看是否安装了Java环境: java -version没有安装的先去安装JDK&#xff1a;Linux 安装 JDK 官网下载zooKeeper 官网下载zooKeeper&…

基于 YOLOv8 的自定义数据集训练

图1.1&#xff1a;YOLOv8初始测试 YOLOv8&#x1f525;于 2023年1月10日由Ultralytics发布。它在计算机视觉方面提供了进展&#xff0c;带来了对我们感知、分析和理解视觉世界的巨大创新。它将为各个领域带来前所未有的可能性。 在速度、准确性和架构方面进行了相当大的改进。它…

vs的常用配置【以及vs常用的快捷键】

1、颜色设置 (1) 编译器的主题颜色设置 (2) 字体和颜色设置 (3) 字体大小 更快捷的修改字体大小方式&#xff1a;ctr鼠标滚轮 2、行号设置 默认就有&#xff0c;不用设置了 3、把解决方案资源管理器移动到左边 4、设置打开错误列表 5、自动保存-要手动使用快捷键 ctrs 代码…

DolphinScheduler×T3出行 | 打造车联网一站式数据应用交互体验

点击蓝字 关注我们 用户案例 | T3 出行 业务挑战 作为一家车联网驱动的公司&#xff0c;T3出行汇聚了“人、车、路、云”各端的海量数据。为了承载如此多元化的数据以更好地释放数据价值&#xff0c;T3出行构建了以Apache Hudi为基础的企业级的数据湖&#xff0c;并在此之上搭建…

Nginx rewrite ——重写跳转

Nginx常见模块 http http块是Nginx服务器配置中的重要部分&#xff0c;代理、缓存和日志定义等绝大多数的功能和第三方模块的配置都可以放在这模块中。作用包括&#xff1a;文件引入、MIME-Type定义、日志自定义、是否使用sendfile传输文件、连接超时时间、单连接请求数上限等…

代码随想录算法训练营第三十六天|435. 无重叠区间、763.划分字母区间 、56. 合并区间

文章目录 重叠问题435. 无重叠区间763.划分字母区间:star:56. 合并区间 重叠问题 这几道题都是判断区间重叠&#xff0c;区别就是判断区间重叠后的逻辑。 435. 无重叠区间 链接:代码随想录 解题思路&#xff1a; 这道题和射气球的题几乎思路一样 不断求出重叠的最小右区间&a…

【Spring篇】Spring相关概念

&#x1f353;系列专栏:Spring系列 &#x1f349;个人主页:个人主页 目录 一、介绍 &#x1f34a;1.为什么要学? &#x1f34d;2.学什么? &#x1f353;3.怎么学? 二、Spring相关概念 &#x1f352;1.Spring家族 &#x1f345;2.了解Spring发展史 &#x1f350;3.Spr…

Centos7 系列:磁盘挂载和磁盘扩容(新加硬盘方式)

磁盘挂载和磁盘扩容 一、系统环境二、磁盘挂载到新目录&#xff08;磁盘挂载&#xff09;2.1 查找新硬盘2.2 创建挂载目录2.3 创建新分区2.4 创建新物理卷2.5 创建新卷组2.6 创建新逻辑卷2.7 挂载到空目录 三、挂载到已有目录&#xff08;磁盘扩容&#xff09;3.1 查找新硬盘3.…

【Linux】冯诺依曼体系结构与进程的基础知识点

目录 1.冯诺依曼体系结构硬件[2~5]2.为什么要有内存&#xff1f;3.为什么不用CPU中的寄存器做存储单元&#xff1f;4.为什么我们的程序必须先被加载到内存中&#xff1f;5.在硬件层面数据流是如何流向的&#xff1f; 软件[6~10]6.操作系统Operator System7.操作系统的作用8.操作…

能源管理系统在电子厂房中的应用

摘要&#xff1a;以能耗管理系统在工业厂房的应用为例&#xff0c;介绍了系统架构及功能。重点分析能耗管理系统在工业厂房实施过程中遇到的难点&#xff0c;并对系统采集的数据进行分析&#xff0c;提出了相应的节能措施&#xff0c;帮助该业厂房达到节约能耗和运行费用的目的…