在C语言中,有时候并不能确定调用函数的参数个数, 虽然可以用传递一个数组或结构体的方法解决,但也可以用C语言提供的可变长参数, printf就是一个非常典型的例子, 还可以使用C++11中的可变参数模板来解决。
可变长参数
在C语言,主要使用va_start,va_arg, va_end, 三个宏来使用可变长参数。
#include <iostream>
#include <cstdarg>
using namespace std;
void Print(int n, ...)
{
va_list args; //va_list的变量, 指向传进来的可变长参数
va_start(args, n); //使args变量指向第一个参数, n是可变参数最左边的参数
for (int i = 0; i < n; i++)
{
int arg = va_arg(args, int); //返回一个int类型的指, 并使args指向下一个参数
//va_arg的第二个参数指定的是要返回的变量类型
cout << arg << endl;
}
va_end(args); //清空va_list可变参数列表
}
int main()
{
Print(5, 1, 2, 3, 4, 5);
system("pause");
return 0;
}
可变参数模板
可变参数模板是C++11提供的,它比可变长参数更加安全。可变参数模板的使用只要有可变参数模板的定义和可变参数模板的解包构成。
一般的定义方法为:
template <typename... Args>
void Print(Args... args);
template<typename... Args>
class Print<Args...>;
第一个定义的是函数使用可变参数模板,第二个是类使用可变参数模板。
对函数使用可变参数模板
//递归终止函数
template <typename T>
void Print(T t)
{
cout << t << endl;
}
//展开函数
template <typename T, typename... Args>
void Print(T t, Args... args)
{
cout << t << endl;
Print(args...); //对可变参数模板进行递归展开
}
int main()
{
Print(10, 5.66, 'a', "Hello");
system("pause");
return 0;
}
Print(10, 5.66, 'a', "Hello")先调用Print(T t, Args... args)不断递归展开:
第一步: 调用Print(T t, Args... args),t = 10,args = (5.66, 'a', "Hello")
第二步: 输出t,调用Print(T t, Args... args), t = 5.66, args = ('a', "Hello")
第三步:输出t,调用Print(T t, Args... args), t = 'a', args = ("Hello")
第四步:输出t后,调用Print(T t), t = "Hello"
第五步:输出t, 结束
具体的堆栈信息和结果:
对类使用可变参数模板
//类模板声明
template<typename... Args>
class Print;
//类模板定义
//通过继承方式展开参数包
template<typename T, typename... Args>
class Print<T, Args...> : public Print<Args...>
{
public:
Print()
{
cout << "class Print<T, Args...>" << endl;
}
};
//递归终止
template<typename T>
class Print<T>
{
public:
Print()
{
cout << "class Print<T>" << endl;
}
};
int main()
{
Print<int, char, float, double> print;
system("pause");
return 0;
}
第一步:调用类class<T, Args...>Print的定义, T = int, args = (char, float, double)
第二步:调用类class<T, Args...>Print的定义, T = char, args = (float, double)
第三步:调用类class<T, Args...>Print的定义, T = float, args = (double)
第四步: 调用类claas<T>Print的定义, T = double
第五步:调用类class<T>Print的构造函数Print()
第六步:调用类class<T, Args>Print的构造函数Print()
第七步:调用类class<T, Args>Print的构造函数Print()
第八步:调用类class<T, Args>Print的构造函数Print()
结束
具体的调用堆栈和输出结果: