C++11 --- 可变参数模板

序言

 不知道大家有没有细细研究过在 C 语言 中的 printf 函数,也许我们经常使用他,但是我们可能并不是那么了解他。先看一下调用格式:int printf ( const char * format, ... );,在这里的 format 代表我们的输出格式,后面的 ... 省略号这又是什么呢,这代表 可变参数,你可以传递任意数量的参数。这是怎么实现的呢?


1. C 中的可变参数

1.1 可变参数的概念

 可变参数是指在函数定义中,允许传入不定数量的参数的一种机制。在编程语言中,可变参数使得函数能够更加灵活地处理不同数量的输入。

1.2 实现可变参数

 在实现可变参数的函数之前,我们先认识几个函数:

stdarg.h 头文件

 为了处理可变参数,C 语言 标准库提供了 stdarg.h 头文件,它定义了一组宏来访问这些参数。这些宏包括:

  • va_list:一个类型,用于声明一个变量,该变量可以用来遍历函数的参数列表。
  • va_start(ap, last_arg):初始化 va_list 变量 aplast_arg 是最后一个固定参数的名字,ap 将用来遍历所有后续的可变参数。
  • va_arg(ap, type):返回 ap 指向的下一个参数,并将 ap 更新为指向下一个参数的指针。type 参数指定了期望的参数类型。
  • va_end(ap):清理 va_list 变量 ap,结束对可变参数列表的遍历。

现在我们实现一个简单的打印数字的可变参数函数:

void PrintNums(int cnt, ...)
{va_list ap;// 初始化va_start(ap, cnt);// 遍历for (int i = 0; i < cnt; i++){// 遍历参数包中的所有参数int num = va_arg(ap, int);std::cout << num << ' ';}std::cout << std::endl;// 释放va_end(ap);
}int main()
{// 第一个参数代表可变参数的个数PrintNums(5, 1, 2, 3, 4, 5);return 0;
}

最后的输出结果也和我们的预期一致:

1 2 3 4 5


1.3 可变参数的原理

 首先我们传递我们的参数时,是 从右到左依次入栈,如下图:
在这里插入图片描述
注意:在这里不要被图像误导,参数占的空间其实很小,只是为了美观画的大一点

通过查看 va_list 的定义 — typedef char* va_list; ,我们发现其实他就是一个 char* 指针。现在该指针需要指向可变参数的起始部分,所以我们需要传递 cnt 过去,对该指针进行初始化后自然就指向了可变参数的起始地址:
在这里插入图片描述
之后我们取数据的时候告诉指针,这是一个 int 类型,你一次性要取 4 / 8 个字节才是完整的数据。之后该指针一直重复取数据的参数,直至遇到结束条件(在这里是 i == cnt)。

 原理似乎也没有那么复杂,但是当可变参数遇到模板时…


2. C++ 中的可变参数模板

2.1 可变参数模板

 在 C++ 中,可变参数模板允许你定义可以 接受任意数量模板参数的模板函数或模板类。这是通过使用模板参数包(template parameter pack)和函数参数包(function parameter pack)来实现的。

2.2 实现可变参数模板

 可变参数模板实际使用起来是比较别扭的,比如这里我就简单实现一个打印多个类型的函数:

void MyPrint()
{std::cout << std::endl;
}template <class T, class... Args>
void _MyPrint(const T &val, Args... args)
{std::cout << val << ' ';_MyPrint(args...);
}template <class... Args>
void MyPrint(Args... args)
{_MyPrint(args...);
}int main()
{MyPrint(1, 1.2, 'A', "ABCD");return 0;
}

输出结果也没有任何的问题:

1 1.2 A ABCD

这个方案的逻辑是递归的去解析参数包,每次取出一个参数直至参数取为空。

 接下来还有一个方案,实现的方式稍微简单一些:

template <class T>
int _MyPrint(const T& val)
{std::cout << val << " ";return 0;
}template <class... Args>
void MyPrint(Args... args)
{int arr[] = {_MyPrint(args)...};std::cout << std::endl;
}int main()
{MyPrint(1, 1.2, 'A', "ABCD");return 0;
}

当然结果肯定和方案一是一致的,但是我们又该怎么理解呢:

  1. 当我们编译程序时需要为这个数组申请指定大小的空间
  2. 但是怎么获取数组中有多少元素呢
  3. 数组中的函数执行一次就有一个返回值,所以执行多少次就有多少元素
  4. 那么函数具体执行多少次呢
  5. 该函数需要一个参数,所以参数包里的参数数量决定执行次数
  6. 执行该函数时我们就会处理一个参数直至参数被使用完

但是很少有让我们实现可变参数模板的场景,大家当作了解一下。


3. 可变参数模板的应用

 就拿容器 vector 举例子,它常使用 insert,push_back 这两个方法添加元素,为了提高效率通过可变参数模板,新的插入元素的方法 emplace, emplace_back 由此而生。

 他的怎么高效的呢?举个栗子来比较一下:

// 方式一
std::string s = "ABC";
vec.push_back(s);// 方式二
vec.push_back(std::string("ABC"));// 方式三
vec.emplace_back("ABC");

我们在这里来比较三者的效率:

  • 方案一:构造函数 + 拷贝构造
  • 方案二:构造函数 + 移动构造
  • 方案三:构造函数

emplace_back直接在容器内构造对象可以避免多余的复制或移动操作,提高性能。
并且 emplace_back 是兼容 push_back 的使用的,所以在使用时大家尽量使用前者。


4. 总结

 在这篇文中我们首先介绍了在 C 语言 中的可变参数,之后简单讲解了 C++ 中的可变参数模板的使用以及应用。

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

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

相关文章

欧拉下搭建第三方软件仓库—docker

1.创建新的文件内容 切换目录到etc底下的yum.repos.d目录&#xff0c;创建docker-ce.repo文件 [rootlocalhost yum.repos.d]# cd /etc/yum.repos.d/ [rootlocalhost yum.repos.d]# vim docker-ce.repo 编辑文件,使用阿里源镜像源&#xff0c;镜像源在编辑中需要单独复制 h…

华为防火墙 nat64

如果设备接收到的IPv6报文的前缀是设备为NAT64定义的前缀&#xff0c;说明报文的目的地址是IPv4网络&#xff0c;报文将经过NAT64处理后被转发至IPv4网络。 如果设备接收到的IPv6报文的前缀不是设备为NAT64定义的前缀&#xff0c;说明报文的目的地址是IPv6网络&#xff0c;报文…

网站钓鱼——挂马技术手段介绍

更多网安实战内容&#xff0c;可前往无问社区查看http://wwlib.cn/index.php/artread/artid/10194.html 网站挂马目前已经成为流氓软件以及红队人员快速获取目标主机权限的常用手段之一&#xff0c;在长时间的实战中也是出现了层出不穷的钓鱼方法&#xff0c;这次分享一下实际…

【北京迅为】《STM32MP157开发板使用手册》-第十三章 编译QtE5.12文件系统

iTOP-STM32MP157开发板采用ST推出的双核cortex-A7单核cortex-M4异构处理器&#xff0c;既可用Linux、又可以用于STM32单片机开发。开发板采用核心板底板结构&#xff0c;主频650M、1G内存、8G存储&#xff0c;核心板采用工业级板对板连接器&#xff0c;高可靠&#xff0c;牢固耐…

内网中的RDP利用

学习参考 https://www.freebuf.com/articles/network/276242.html能跟着实操的都实操一下。熟悉一些命令&#xff0c;过程。 实验环境&#xff1a;win2008&#xff0c;192.168.72.139 两个用户&#xff1a; administrator&#xff0c;shizuru RDP服务 确定/开启 RDP服务确…

Chainlit集成Mem0使用一个拥有个性化AI记忆的网页聊天应用

前言 Mem0 简介&#xff0c;可以看我上一篇文章《解决LLM的永久记忆的解决方案-Mem0实现个性化AI永久记忆功能》。本篇文章是对Mem0 实战使用的一个示例。通过Chainlit 快速实现ui界面和open ai的接入&#xff0c;通过使用Mem0 实现对聊天者的对话记录的记忆。 设计实现基本原…

828华为云征文|部署多媒体流媒体平台 Plex

828华为云征文&#xff5c;部署多媒体流媒体平台 Plex 一、Flexus云服务器X实例介绍1.1 云服务器介绍1.2 性能模式1.3 计费模式 二、Flexus云服务器X实例配置2.1 重置密码2.2 服务器连接2.3 安全组配置 三、部署 Plex3.1 Plex 介绍3.2 Docker 环境搭建3.3 Plex 部署3.4 Plex 使…

张家辉新作《重生》内地票房逆袭

由张家辉领衔主演的电影《重生》在票房大获成功&#xff0c;击败多部同期中西强片&#xff0c;成为今年暑期档的最大黑马。张家辉在片中饰演的角色原本拥有幸福家庭&#xff0c;为了复仇走上亡命之徒的道路&#xff0c;影片中他再度展现了影帝级别的演技&#xff0c;受到网民和…

CCF推荐A类会议和期刊总结(计算机网络领域)- 2022

CCF推荐A类会议和期刊总结&#xff08;计算机网络领域&#xff09;- 2022 在中国计算机学会&#xff08;CCF&#xff09;的推荐体系中&#xff0c;A类会议和期刊代表着计算机网络领域的顶尖水平。这些会议和期刊不仅汇集了全球顶尖的研究成果&#xff0c;还引领着该领域的前沿发…

合碳智能 × Milvus:探索化学合成新境界——逆合成路线设计

合碳智能&#xff08;C12.ai&#xff09;成立于2022年&#xff0c;致力于运用AI和具身智能技术&#xff0c;为药物研发实验室提供新一代智能化解决方案&#xff0c;推动实验室从自动化迈向智能化&#xff0c;突破传统实验模式与人员的依赖&#xff0c;解决效率和成本的瓶颈&…

解决浏览器自动将http网址转https

删除浏览器自动使用https的方式 在浏览器地址栏输入&#xff1a;chrome://net-internals/#hsts PS:如果是edge浏览器可输入&#xff1a;edge://net-internals/#hsts 在Delete domain security policies搜索框下&#xff0c;输入要删除的域名,然后点击delete 解决方法&#…

回收玻璃减薄中的氢氟酸

回收玻璃减薄中的氢氟酸是一个重要的环保和资源再利用环节。在玻璃减薄过程中&#xff0c;氢氟酸作为主要的化学蚀刻剂&#xff0c;与玻璃基板表面的二氧化硅等成分发生反应&#xff0c;实现玻璃的减薄。然而&#xff0c;随着反应的进行&#xff0c;氢氟酸的浓度会逐渐降低&…

MyQql性能诊断与实践

获取更多免费资料&#xff0c;见下图

证书学习(四)X.509数字证书整理

目录 一、X.509证书 介绍1.1 什么是 X.509证书?1.2 什么是 X.509标准?1.3 什么是 PKI?二、X.509证书 工作原理2.1 PKI 的基础——加密算法2.2 PKI 证书编码三、X.509证书 结构3.1 证书字段3.2 证书扩展背景: 我们在日常的开发过程中,经常会遇到各种各样的电子证书文件,其…

新电脑Win11系统想要降级为Win10怎么操作?

前言 现在的电脑大部分都是Windows 11系统&#xff0c;组装机还好一些&#xff0c;如果想要使用Windows 10&#xff0c;只需要在安装系统的时候选择Windows 10镜像即可。 但是对于新笔记本、厂商的成品机、一体机来说&#xff0c;只要是全新的电脑&#xff0c;基本上都是Wind…

快速入门游戏领域,开发游戏需要哪些技术?

在这个充满创意和技术的时代&#xff0c;游戏行业成为众多创新人才追求梦想的热土。对于准备踏入这个充满挑战与机遇的领域的新人来说&#xff0c;了解游戏开发流程是至关重要的。 游戏市场蓬勃发展&#xff0c;游戏行业未来行情可观&#xff0c;在这个充满创意和技术的时代&a…

8. GIS数据分析师岗位职责、技术要求和常见面试题

本系列文章目录&#xff1a; 1. GIS开发工程师岗位职责、技术要求和常见面试题 2. GIS数据工程师岗位职责、技术要求和常见面试题 3. GIS后端工程师岗位职责、技术要求和常见面试题 4. GIS前端工程师岗位职责、技术要求和常见面试题 5. GIS工程师岗位职责、技术要求和常见面试…

vue3 前端实现pdf打印预览 printjs

在utils建print.ts文件 interface PrintFunction {extendOptions: Function;getStyle: Function;setDomHeight: Function;toPrint: Function; }const Print function (dom, options?: object): PrintFunction {options options || {};// ts-expect-errorif (!(this instanc…

电脑技巧:如何在Win11电脑上调整设置,让屏幕更加护眼?

目录 一、调整屏幕亮度 二、启用夜间模式 三、调整色彩设置 四、使用第三方护眼软件 五、保持良好的用眼习惯 总结 随着长时间使用电脑的人越来越多,护眼问题也变得越来越重要。Win11作为更新的操作系统,提供了更多的设置选项来帮助我们保护眼睛。本文将详细介绍如何在…

清华计算几何--凸Polygon的相交问题

凸Polygon和相交定义 本节只讨论凸Polygon的问题&#xff0c;不涉及凹Polygon. 相交包含了边相交和完全包含。 凸Polygon相交的两个问题 Detection(检测) 判断两个凸Polygon是否相交&#xff0c;至于相交部分是什么不关心. Construction(构造) 求出两个凸Polygon具体相交…