C++中可变参函数三种实现方法:
1.使用C语言头文件<stdarg.h>中的可变参宏
va_list
:用于定义一个va_list类型的变量,为后面的扩展可变参列表做准备;
eg: va_list pvar;
va_start
:用于初始化va_list类型的变量
eg: va_start(pvar,tvar);
tvar为离可变参(…)最近的一个固定参数va_arg
:从变参列表中获取一个参数
eg: va_arg(pvar,data_type);
data_type表示数据类型:
int b=va_arg(pvar,int);
va_end
:关闭变参扩展,进行后续的内存回收工作;
eg : va_end(pvar)
使用事项:
- 在使用结束之后,一定要使用va_end进行清理工作;因为可变参的机制类似于动态开辟空间,而var_end就相当于内存回收。
- 在使用时,需要知道传递参数的类型,以及参数的个数;这就规定,在定义函数的时候至少有一个固定的形参,用于传递函数目前的变参的个数。
- 在函数的定义中,需要变长参列表在固定参之后,即:void func(int cnt,…);
- 该方法不安全,容易出现内存溢出,或是泄露的问题,而且变参列表是顺序的,不能回溯之前的参数,就相当于将变参放入了一个队列中,每执行va_arg(pvar,data_type)一次,pvar指针就往后移动一次,就往后取出一个数据.
int mymax(int cnt, ...)
{
va_list pvar;
va_start (pvar, cnt);
int ret = va_arg (pvar, int); //获取变参列表中的值
for (int i= 1; i< cnt; i++)
{
int b = va_arg(pvar, int);
ret = ret > b ? ret :b;
}
va_end(pvar);
return ret;
}
int main()
{
mymax(2, 5, 12);
mymax(3, 4, 10, 5);
}
使用C++ 11标准中的initializer_list
initializer_list是一种容器,和vector差不多,这个使用就不要求变参列表的位置,使用方法,在这里传递的参数至少一个。
#include <initializer_list>
int mymax(initializer_list<int> tdat)
{
int lret=*(tdat.begin()); // 取第一个元素的值
for (auto p:tdat)
{
lret=lret>p?lret:p; // 求最大值
}
return lret;
}
int main()
{
//传递参数时,需要使用列表形式传递
cout << mymax({1,3,6,4,5}) << endl;
}
使用C++可变参模板
使用该方法有着很多的优点,但是因为不能直接获得包中的参数,存在一个问题就是怎样展开参数包,而展开参数包的方法有:递归方法展开、逗号表达式展开法。这种方法可以传递0,1,2…个参数。
递归方法:
使用递归方法展开,就和普通的递归函数使用类似,需要一个递归终止函数
// 方式1:
template<class T1,class...T2>
double mymax(T1 p, T2... arg)
{
//T2是模板包 arg为参数包
double ret = mymax(arg...); // 参数包扩展
if (p >ret)
return p;
return ret;
}
// 必须有一个递归终止函数
template<class ret_type>
ret_type mymax(ret_type p) //递归终止函数
{
return p;
}
int main()
{
//传递参数时,需要使用列表形式传递
cout << mymax(1,4,4,4) << endl;
}
// 方式2:
// 使用时需要一个固定参数,用于包扩展,但是函数不要求一定需要参数
template<class T1, class ...T2>
void printArgs(T1 p, T2... args)
{
cout << "paraneters:"<< p << endl;
printArgs(args...);
}
void printArgs()
{
cout <<"function end!"<< endl;
}
int main()
{
printArgs(1, 2, 3, 4, 5);
}
逗号表达式展开法:
template<class ...T2>
void printArgs(T2...args)
{
//逗号表达式解包,其实质就是使用initializer_list进行初始化数组
int a[] ={(cout<<args<<endl,0)... }
//sizeof前的...用于计算参数的个数
cout<<"参数个数为:"<< sizeof...(args)<< endl;
}
int main()
{
printArgs(1, 2, 3, 4, 5);
}