C++实现变参函数的三种方法

1.将函数形参声明为C++11中的initializer_list标准库类型

步骤:

  1. 函数原型中使用实例化initializer_list模板代表可变参数列表
  2. 使用迭代器访问initializer_list中的参数
  3. 传入实参写入{}中
#include<iostream>
#include <initializer_list>
using namespace std;

int sum(initializer_list<int> il);  //函数原型用int实例化initializer_list作为形参

int sum(initializer_list<int> il) {
	int sum = 0;
	for (auto p = il.begin(); p != il.end(); p++)   //使用迭代器访问参数
		sum += *p;
	return sum;
}

int main() {
	cout << sum({ 1,2,3,4,5,6,7,8,9,10 }) << endl;
	system("pause");
	return 0;
}

注意:

  1. C++11标准
  2. 参数放入{}中传递
  3. 函数原型initializer_list与普通形参相同,位置与参数类型不限
  4. 同一个initializer_list中参数具有相同的类型,实质上是容器类模板

2.继承C语言,形参声明为省略符,函数实现时用参数列表宏访问参数

步骤:(使用四个宏va_list、va_start(va_list, arg)、va_arg(va_list, type)、va_end(va_list),在头文件stdarg.h中)

  1. 函数原型中使用省略号
  2. 函数定义中创建一个va_list变量
  3. 初始化va_list变量
  4. 访问参数列表
  5. 完成清理工作
#include<iostream>
#include <stdarg.h>
using namespace std;

int sum(int count, ...); 

int sum(int count, ...) {	//count 表示可变参数个数
	va_list ap;				//声明一个va_list变量
	va_start(ap, count);	//初始化,第二个参数为最后一个确定的形参

	int sum = 0;
	for (int i = 0; i < count; i++)
		sum += va_arg(ap, int); //读取可变参数,第二个参数为可变参数的类型

	va_end(ap);					//清理工作 
	return sum;
}

int main() {
	cout <<sum(5,1,2,3,4,5)<< endl;
	system("pause");
	return 0;
}

注意:

  1. 省略号必须在参数列表的末尾
  2. 运行时确定可变参数类型与个数,个数:实参确定,类型:既有约定
  3. **va_end()**清理内存
  4. 只能实现顺序访问
  5. 极不安全:不检查实参数量

3.C++泛型,可变参数模板实现

模板参数包:零个或多个类型参数的集合

函数参数包:零个或多个非类型参数的集合(除浮点数、字符串和类对象,编译期确认结果)

步骤:

  1. 编写含有模板参数包和函数参数包的模板参数
  2. 函数定义递归调用自己,每一步递归参数包中参数减一
  3. 编写处理边界情况的模板
#include<iostream>
#include <stdarg.h>
using namespace std;

//用来终止递归并答应最后一个元素的函数
//此函数必须在可变参数版本的print定义之前声明
template <typename T>
std::ostream &print(std::ostream &os, const T &t) {
	return os << t;                //包中最后一个元素
}
//包中除最后一个元素之外的其他元素都会调用这个版本的pirnt
template <typename T, typename... Args>
std::ostream &print(std::ostream &os, const T &t, const Args &... rest) {
	os << t << ",";               //打印第一个实参,包中元素减一
	return print(os, rest...);    //递归调用,打印剩余实参
}

int main() {
	print(std::cout,1,'A',"lzw",415,true);
	system("pause");
	return 0;
}

注意:

  1. 首先处理边界情况
  2. 参数包在列表最右侧,从左至右展开
  3. 模板实现函数重载,编译器根据参数类型自动生成

三种方法比较

  1. 若非必要,不使用可变参数函数
  2. 尽量不用可变参数宏,安全性差
  3. initializer_list最为简单实用
  4. 可变参数模板支持不同类型参数,但实例过多会使得代码体积增大,递归影响效率

最后给大家推荐一个LinuxC/C++高级架构系统教程的学习资源与课程,可以帮助你有方向、更细致地学习C/C++后端开发,具体内容请见 https://xxetb.xetslk.com/s/1o04uB 链接: link

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值