C ++中函数的可变参数数量

我如何在C ++中的函数中拥有可变数量的参数。

C#中的模拟:

public void Foo(params int[] a) { for (int i = 0; i < a.Length; i++) Console.WriteLine(a[i]); } public void UseFoo() { Foo(); Foo(1); Foo(1, 2); } 

Java模拟:

 public void Foo(int... a) { for (int i = 0; i < a.length; i++) System.out.println(a[i]); } public void UseFoo() { Foo(); Foo(1); Foo(2); } 

这些被称为Variadic函数 。 维基百科列出了C ++的示例代码 。

要在C编程语言中可移植地实现可变参数函数,应使用标准的stdarg.h头文件。 旧的varargs.h标头已被弃用,转而使用stdarg.h。 在C ++中,应该使用头文件cstdarg

要创建可变参数函数,必须在参数列表的末尾放置省略号( ... )。 在函数体内,必须定义va_list类型的变量。 然后可以使用宏va_start(va_list, last fixed param)va_arg(va_list, cast type)va_end(va_list) 。 例如:

 #include  double average(int count, ...) { va_list ap; int j; double tot = 0; va_start(ap, count); //Requires the last fixed parameter (to get the address) for(j=0; j 

真正的C ++解决方案是可变参数模板。 您需要一个相当新的编译器,并在需要时启用C ++ 11支持。

处理“使用所有函数参数执行相同操作”问题的两种方法:递归地,并且使用丑陋(但非常符合标准)的解决方案。

递归解决方案看起来像这样:

 template void print(ArgTypes... args); template void print(T t, ArgTypes... args) { std::cout << t; print(args...); } template<> void print() {} // end recursion 

它为每个参数集合生成一个符号,然后为递归的每个步骤生成一个符号。 至少可以说这不是最理想的,所以SO的优秀C ++人员想到了滥用列表初始化的副作用的一个很好的技巧 :

 struct expand_type { template expand_type(T&&...) {} }; template void print(ArgTypes... args) { expand_type{ 0, (std::cout << args, 0)... }; } 

代码不是为一百万个略有不同的模板实例生成的,作为奖励,您可以获得函数参数的保留顺序。 有关此解决方案的详细信息,请参阅其他答案。

除了其他答案,如果你只是想传递一个整数数组,为什么不:

 void func(const std::vector& p) { // ... } std::vector params; params.push_back(1); params.push_back(2); params.push_back(3); func(params); 

但是,您无法在参数,表单中调用它。 您必须使用答案中列出的任何可变参数函数。 C ++ 0x将允许可变参数模板,这将使其类型安全,但现在它基本上是内存和转换。

你可以模拟某种可变参数 – >向量的东西:

 // would also want to allow specifying the allocator, for completeness template  std::vector gen_vec(void) { std::vector result(0); return result; } template  std::vector gen_vec(T a1) { std::vector result(1); result.push_back(a1); return result; } template  std::vector gen_vec(T a1, T a2) { std::vector result(1); result.push_back(a1); result.push_back(a2); return result; } template  std::vector gen_vec(T a1, T a2, T a3) { std::vector result(1); result.push_back(a1); result.push_back(a2); result.push_back(a3); return result; } // and so on, boost stops at nine by default for their variadic templates 

用法:

 func(gen_vec(1,2,3)); 

请参阅C,Objective-C,C ++和D中的Variadic函数

您需要包含stdarg.h ,然后使用va_listva_startva_argva_end ,如维基百科文章中的示例所示。 它比Java或C#更麻烦,因为C和C ++对varargs的内置支持有限。

在C ++ 11及更高版本中,您还可以使用初始化列表。

 int sum(const initializer_list &il) { int nSum = 0; for (auto x: il) nSum += x; return nsum; } cout << sum( { 3, 4, 6, 9 } ); 

如果您不关心可移植性,可以使用gcc的语句表达式 将此C99代码移植到C ++:

 #include  int _sum(size_t count, int values[]) { int s = 0; while(count--) s += values[count]; return s; } #define sum(...) ({ \ int _sum_args[] = { __VA_ARGS__ }; \ _sum(sizeof _sum_args / sizeof *_sum_args, _sum_args); \ }) int main(void) { std::printf("%i", sum(1, 2, 3)); } 

您可以使用C ++ 0x’slambda表达式执行类似操作,但我正在使用的gcc版本(4.4.0)不支持它们。

GManNickG和Christoph的答案很好,但是可变函数允许你按照你想要的方式输入参数,而不仅仅是整数。 如果您将来想要将不同类型的许多变量和值推送到函数中而不使用可变参数函数,因为它对您来说太难或太复杂,或者您不喜欢使用它的方式或者您不喜欢使用它我想要包含所需的标题来使用它,那么你总是可以使用void**参数。

例如,Stephan202发布:

 double average(int count, ...) { va_list ap; int j; double tot = 0; va_start(ap, count); //Requires the last fixed parameter (to get the address) for(j=0; j 

这也可以写成:

 double average(int count, void** params) { int j; double tot = 0; for (j=0; j 

现在就像这样使用它:

 int _tmain(int argc, _TCHAR* argv[]) { void** params = new void*[3]; double p1 = 1, p2 = 2, p3 = 3; params[0] = &p1; params[1] = &p2; params[2] = &p3; printf("Average is: %g\n", average(3, params)); system("pause"); return 0; } 

完整代码:

 #include "stdafx" #include  double average(int count, void** params) { int j; double tot = 0; for (j=0; j 

OUTPUT:

平均值是:2

按任意键继续 。 。 。

我在c ++ builder xe.xx中这样做我的:

 String s[] = {"hello ", " unli", " param", " test"}; String ret = BuildList(s, 4); String BuildList(String s[], int count) { for(int i = 0; i < count; i++) { //.... loop here up to last s[i] item ... } }