c++ 可变参数的三种实现方式

news2024/11/16 10:43:39

c++ 可变参数

方法一: C语言的: va_list1

#include <stdio.h>
#include <stdarg.h>

int add_nums(int count, ...)
{
    int result = 0;
    va_list args;
    va_start(args, count); // C23 起能省略 count
    for (int i = 0; i < count; ++i) {
        result += va_arg(args, int);
    }
    va_end(args);
    return result;
}


int main(void)
{
    printf("%d\n", add_nums(4, 25, 25, 50, 50));
}
  • \1. 函数本身并不知道传进来几个参数,比如我现在多传一个参数,或者少传一个参数,那么函数本身是检测不到这个问题的。这就可能会导致未定义的错误。
  • \2. 函数本身也不知道传进来的参数类型。以上面的例子,假如我把第二个参数1.0改成一个字符串,又如何?答案就是会得到未定义的错误,也就是不知道会发生什么。
  • \3. 对于可变长参数,我们只能用__cdecl调用约定,因为只有调用者才知道传进来几个参数,那么也只有调用者才能维持栈平衡。如果是__stdcall,那么函数需要负责栈平衡,可是函数本身根本不知道有几个参数,函数调用结束后,根本不知道需要将几个参数pop out。(注:某些编译器如VS,如果用户写了个__stdcall的可变长参数函数,VS会自动转换成__cdecl的,当然这是编译器干的事情)

方法二:C++语言的: initializer_list

  • initializer_list API
void my_print1(int a, initializer_list<string> il)
{
    cout << a << endl;
    for (auto &i : il)
        cout << i << " ";
    cout << endl;
}

//函数调用
int main()
{
    my_print1(2, {"lxb", "zhj"});
    return 0;
}

方法三:c++ 使用可变参数模板

一个可变参数模板(variadic template)就是一个接受可变数目参数的模板函数或模板类。可变数目的参数被称为参数包(parameter packet)。存在两种参数包:模板参数包(template parameter packet),表示零个或多个模板参数;函数参数包function parameterpacket),表示零个或多个函数参数。

C++11新特性: 可变参数模版

3.1 可变参数个数

  • 可变参数的个数:
template<class... Types>
struct count
{
    static const std::size_t value = sizeof...(Types);
};

3.2 递归展开可变参数

  • 通过递归的方式展开
  1. 递归展开需要考虑爆栈的情况。 说到这里,ubuntu(linux) 默认栈大小8M(使用命令 ulimit -a查看), Win下,Visual Studio 默认栈大小1M(连接器->系统)。

  2. 需要两个函数:递归终止函数递归函数

  3. 一个例子,输出各个元素。函数参数为参数包的形式,使用递归展开

double Sum2()  // 边界条件
{
    return 0;
}

template<typename T1, typename... T2>
double Sum2(T1 p, T2... arg)
{
    double ret = p + Sum2(arg...);
    return ret;
}

int main() {
    cout << Sum2(2,2,2,2);
}
  • 递归终止改为一个参数
template<class T>
void print(T &t) {cout << t <<'\n';}
 
template<class T, class... Args>
void print(T &t, Args&... rest) {
    cout << t << ' ';
    print(rest...); // 打印剩余参数,注意省略号必须有
}

3.3 逗号表达式展开

使用逗号运算符是为了把几个表达式放在一起。

整个逗号表达式的值为系列中最后一个表达式的值。

从本质上讲,逗号的作用是将一系列运算按顺序执行。

image-20230112231912152

  • 逗号表达式拆包
template <class T>
void PrintArg(T t) 
{
	cout << t << " ";
}
//展开函数
template <class ...Args>
void ShowList(Args... args) 
{
	int arr[] = { (PrintArg(args), 0)... };
	cout << endl;
}
int main()
{
	ShowList(1);
	ShowList(1, 'A');
	ShowList(1, 'A', std::string("sort"));
	return 0;
}

  • 逗号表达式会从左到右依次计算各个表达式,并且将最后一个表达式的值作为返回值进行返回。
  • 将逗号表达式的最后一个表达式设置为一个整型值,确保逗号表达式返回的是一个整型值。
  • 将处理参数包中参数的动作封装成一个函数,将该函数的调用作为逗号表达式的第一个表达式。
  • 这里我们把逗号表达式的最后一个值设为0,此时我参数包里有几个参数,那么就有几个0,也就代表有几个值

当然,这里其实不用逗号表达式也可以,直接给PrintArg函数带上返回值即可完成逗号表达式的功能:

template <class T>
int PrintArg(const T& t)
{
	cout << t << " ";
	return 0;
}
template <class ...Args>
void ShowList(Args... args)
{
	//列表初始化
	int arr[] = { PrintArg(args)... };
	cout << endl;
}

此时可以传入多种类型的参数了,但是不能不传参数,因为数组的大小不能为0,为了支持不传参数,我们需要单独写个无参的ShowList函数,就像无参版的终止函数那样:

//支持无参调用
void ShowList()
{
	cout << endl;
}
template <class T>
int PrintArg(const T& t)
{
	cout << t << " ";
	return 0;
}
template <class ...Args>
void ShowList(Args... args)
{
	//列表初始化
	int arr[] = { PrintArg(args)... };
	cout << endl;
}

这个数组的目的纯粹是为了在数组构造的过程展开参数包。

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

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

相关文章

bresenham algorithm

#! https://zhuanlan.zhihu.com/p/598780689 bresenham algorithm 全象限区域bresenham algorithm计算的python/c实现 bresenham algorithm为计算机图形学中使用像素点显示直线的算法&#xff0c;算法使用整数运算&#xff0c;能大幅提升计算速度。最近概率栅格建图算法中涉及…

CloudCanal实战-Oracle数据迁移同步到PostgreSQL

简述 本篇文章主要介绍如何使用 CloudCanal 构建一条 Oracle 到 PostgreSQL 的数据同步链路 技术要点 缩小的数据库权限要求 CloudCanal 对 Oracle 数据库的高权限要求&#xff0c;主要来自两个面向 DBA 的操作&#xff0c;自动构建字典和 自动切换归档日志&#xff0c;这两…

详解 strtok 函数以及模拟实现

目录 一、strtok 函数的介绍 二、strtok 函数的模拟实现 一、strtok 函数的介绍 函数原型&#xff1a; char* strtok(char* str, const char* delimiters); delimiter n.[计]分隔符&#xff0c;定界符&#xff08;a character that marks the beginning or end of a unit o…

KMP算法详解+动图演示

目录 一、KMP算法简介 二、KMP算法的详细图解 1. 先了解BF算法的基本思路 2. 简单了解KMP算法 3. next数组的引入 4. next数组的代码实现&#xff08;含动态演示&#xff09; 三、KMP算法完整代码 一、KMP算法简介 KMP算法是一种改进的字符串匹配算法&#xff0c;由 …

【算法】二分图判定

目录1.概述2.代码实现3.应用本文参考&#xff1a; LABULADONG 的算法网站 1.概述 &#xff08;1&#xff09;二分图 (Bipartite Graph)&#xff0c;又称为二部图&#xff0c;是图论中的一种特殊模型。 设 G (V, E) 是一个无向图&#xff0c;如果顶点 V 可分割为两个互不相交的…

Unity 和vs2022对接问题

第一个问题&#xff1a;在vs中编写好的程序在unity中预览出现乱码&#xff1b;提示&#xff1a;只要是乱码的问题90%离不开编码表Unity中的编码表是utf-8,而vs中默认的应该是GB2312。英文还好&#xff0c;中文可定就会出现乱码&#xff0c;解决方法也很简单&#xff1a;把vs中的…

【Python基础四】入门级朋友看的超详教程

前言 这是最后一篇基础的文章啦 往期文章&#xff1a; 【Python基础一】入门级朋友看的超详教程 【Python基础二】入门级朋友看的超详教程 【Python基础三】入门级朋友看的超详教程 刚开始接触Python的宝子&#xff0c;有什么不懂的都可以私信我哦 我还准备了大量的免费…

目标检测:YOLO V2思路解读

目标检测&#xff1a;YOLO V2思路解读YOLO V1存在的问题主要改进Batch NormalizationHigh Resolution ClassifierConvolutional With Anchor BoxesDimension ClusterDirect location PredictionFine-Grained FeaturesMulti-Scale TrainingLoss FunctionYOLO V1存在的问题 对于…

使用Redis代替Session实现短信登陆

1.集群的Session共享问题 多台Tomcat并不共享Session存储空间&#xff0c;当请求切换到不同tomcat服务器时会导致数据丢失&#xff1a; 当用户量增多&#xff0c;我们需要进行负载均衡、对tomcat做水平扩展&#xff0c;可是存储在Tomcat里的Session不是共享的&#xff0c;这…

从C和C++内存管理来谈谈JVM的垃圾回收算法设计-上

从C和C内存管理来谈谈JVM的垃圾回收算法设计-上引言C内存模型malloc堆内存分配过程malloc为什么结合使用brk和mmapmalloc如何通过内存池管理Heap区域垃圾收集器引言 本文想和大家来探讨一下JVM是如何对堆内存进行管理和垃圾回收,相关书籍如深入理解JVM第三版中已经介绍过了相关…

OSCP-Vulnhub靶机记录-digitalworldlocal-fall

Vulnhub靶机记录-digitalworldlocal-fall靶机描述安装扫描枚举使用kali自带的FUZZ权限提升靶机描述 靶机地址&#xff1a;https://www.vulnhub.com/entry/digitalworldlocal-fall,726/ Description To celebrate the fifth year that the author has survived his infosec ca…

也来聊聊滑块验证码的那些事

单位做攻防演习&#xff0c;我扮演攻击方尝试破解。发现滑块验证码做了升级&#xff0c;比之前复杂了很多。好在仍然是一维验证&#xff0c;不用太麻烦。https接口里读出的是json对象&#xff0c;先从对象里取出图片转的base64编码&#xff0c;然后把字符串转回成numpy.ndarray…

Verilog HDL 基础语法

一、逻辑值 0: 逻辑低电平&#xff0c;条件为假 1: 逻辑高电平&#xff0c;条件为真 z: 高阻态&#xff0c;无驱动 x: 未知逻辑电平二、实际例子 1. 模块名一般与文件名相同 线网型变量会被映射成一条真实存在的物理连线。 寄存器型变量会被映射成一个寄存器。 2. 参数 para…

2、JavaScript快速入门

2.1 引入JavaScript 内部标签 <!-- 在script标签内写JavaScript(简称js)代码&#xff0c;代码块可以放在head中&#xff0c;也可以放在body中--> <script>// alert:弹窗alert(Hello,world!); //注意以分号结尾 </script>外部引入 hello.js alert(Hello,worl…

分享120个ASP源码,总有一款适合您

ASP源码 分享120个ASP源码&#xff0c;总有一款适合您 链接&#xff1a;https://pan.baidu.com/s/1WwTsUTLS_qLvP-TC1w-1vQ?pwdvxpk 提取码&#xff1a;vxpk 下面是文件的名字&#xff0c;我放了一些图片&#xff0c;文章里不是所有的图主要是放不下...&#xff0c;大家下载…

OB0207 obsidian 自动获取url链接:auto-link-title插件使用

序号解读&#xff1a; 01——软件基础使用、基础语法 02——插件使用 03——综合实战 0 写在前面 Ob社区插件汇总&#xff1a;Airtable - OB社区插件汇总 - Johnny整理 - 每周更新 - B站 Johnny学Explore the "OB社区插件汇总 - Johnny整理 - 每周更新 - B站 Johnny学&qu…

过去一年渲染了3亿帧,助力了63.81亿票房、1150亿播放量丨瑞云渲染年度大事记

2022年&#xff0c;注定是充满未知和挑战的一年。抗疫三年&#xff0c;终于在2022年底迎来放开&#xff0c;我们怀着忐忑的心情告别了核酸、行程码和封控&#xff0c;成为了自己健康的第一负责人。这段时间大家应该都忙着和病毒做斗争吧&#xff0c;瑞云各个岗位的小伙伴们也都…

6.7、万维网(如HTTP超文本传输协议)

1、基本介绍 万维网 WWW (World Wide Web&#xff09;并非某种特殊的计算机网络\color{red}并非某种特殊的计算机网络并非某种特殊的计算机网络。 它是一个大规模的、联机式的信息储藏所&#xff0c;是运行在因特网上的一个分布式应用。 万维网利用网页之间的超链接\color{r…

Web进阶:Day5 移动适配、rem、less

Web进阶&#xff1a;Day5 Date: January 10, 2023 Summary: 移动适配、rem、less 移动适配 移动适配指网页元素的宽高都要随着设备宽度等比缩放 rem &#xff1a; 目前多数企业在用的解决方案 vw / vh&#xff1a;未来的解决方案 rem 目标&#xff1a;能够使用rem单位设置网…

2022年跨境物流指数研究报告

第一章 行业概况 指提供跨境物流服务的行业。跨境物流是指在电子商务环境下&#xff0c;依靠互联网、大数据、信息化与计算机等先进技术&#xff0c;物品从跨境电商企业流向跨境消费者的跨越不同国家或地区的物流活动。 图 物流运输行业产业链结构图 资料来源&#xff1a;资产…