C 可变参数
typedef char* va_list;
void va_start ( va_list ap, prev_param );
type va_arg ( va_list ap, type );
void va_end ( va_list ap );
// 32位机器对int大小向上取整,64位机器对int64大小向上取整,因为参数在栈中传递都要对齐
#define _INTSIZEOF(n) ((sizeof(n)+sizeof(int)-1)&~(sizeof(int) - 1) )
#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) )
#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
#define va_end(ap) ( ap = (va_list)0 )
一个简单的例子
#include<stdio.h>
#include<stdlib.h>
#include<stdarg.h>
void funcarg(int n, ...){
int t;
va_list arg;
va_start(arg, n);
for(int i=0;i<n;i++){
t = va_arg(arg, int);
printf("%d ",t);
}
va_end(arg);
}
int main()
{
funcarg(3,1,2,3);
}
缺点:无法判断参数类型,只能用事先约定好的类型来取值,如果取值类型不对,会出现未知错误。
C++ initializer_list
使用initializer_list可以传递任意多个同类型的参数,类似于vector,是一种模板容器,可以将多个同类型参数打包成一个参数对象,然后传递给函数。
void funcinitial(initializer_list<int> ls){
for(auto x:ls) cout<<x<<" ";
}
缺点:只支持单一类型,只读不写。
C++ 可变参数模板
接受可变参数的模板函数,可变参数称为参数包,包括模板参数包和函数参数包。
编译器从实参推断模板参数类型,并推断参数数目,然后实例化不同版本。
注意需要另外定义非可变参数的版本,负责终止递归。
template<typename T>
void funcvartemplate(T t){
cout<<t<<" ";
}
template<typename T,typename ... Args>
void funcvartemplate(T t, Args ... args){ // 扩展Args
cout<<t<<" ";
funcvartemplate(args...); // 扩展args
}
包扩展,就是将包分解为构成元素,对每个元素应用模式,获得扩展后的列表。
对于上面的例子,第一个扩展操作为扩展模板参数包,为print生成函数参数列表,第二个扩展在对print的调用中,为print生成实参列表。