如何在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);
}
Analog in 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);
}
答案 0 :(得分:42)
这些被称为Variadic functions。维基百科列出example code for C++。
可移植地实现可变参数 C编程中的函数 language,标准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 <stdarg.h>
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<count; j++)
tot+=va_arg(ap, double); //Requires the type to cast to. Increments ap to the next argument.
va_end(ap);
return tot/count;
}
答案 1 :(得分:14)
真正的C ++解决方案是可变参数模板。您需要一个相当新的编译器,并在需要时启用C ++ 11支持。
两种方法来处理&#34;对所有函数参数执行相同的操作&#34;问题:递归地,并且有一个丑陋的(但非常符合标准的)解决方案。
recursive solution看起来有点像这样:
template<typename... ArgTypes>
void print(ArgTypes... args);
template<typename T, typename... ArgTypes>
void print(T t, ArgTypes... args)
{
std::cout << t;
print(args...);
}
template<> void print() {} // end recursion
它为每个参数集合生成一个符号,然后为递归的每一步生成一个符号。这至少可以说是次优的,所以the awesome C++ people here at SO想到了a great trick abusing the side effect of a list initialization:
struct expand_type {
template<typename... T>
expand_type(T&&...) {}
};
template<typename... ArgTypes>
void print(ArgTypes... args)
{
expand_type{ 0, (std::cout << args, 0)... };
}
代码不是针对一百万个略有不同的模板实例生成的,作为奖励,您可以获得函数参数的保留顺序。有关此解决方案的详细信息,请参阅其他答案。
答案 2 :(得分:5)
除了其他答案之外,如果你只是想传递一个整数数组,为什么不呢:
void func(const std::vector<int>& p)
{
// ...
}
std::vector<int> params;
params.push_back(1);
params.push_back(2);
params.push_back(3);
func(params);
但是你不能在参数,表格中调用它。您必须使用答案中列出的任何可变参数函数。 C ++ 0x将允许可变参数模板,这将使其类型安全,但现在它基本上是内存和转换。
您可以模拟某种可变参数 - &gt;向量事物:
// would also want to allow specifying the allocator, for completeness
template <typename T>
std::vector<T> gen_vec(void)
{
std::vector<T> result(0);
return result;
}
template <typename T>
std::vector<T> gen_vec(T a1)
{
std::vector<T> result(1);
result.push_back(a1);
return result;
}
template <typename T>
std::vector<T> gen_vec(T a1, T a2)
{
std::vector<T> result(1);
result.push_back(a1);
result.push_back(a2);
return result;
}
template <typename T>
std::vector<T> gen_vec(T a1, T a2, T a3)
{
std::vector<T> 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));
答案 3 :(得分:5)
在C ++ 11及更高版本中,您还可以使用初始化列表。
int sum(const initializer_list<int> &il)
{
int nSum = 0;
for (auto x: il)
nSum += x;
return nsum;
}
cout << sum( { 3, 4, 6, 9 } );
答案 4 :(得分:3)
请参阅Variadic functions in C, Objective-C, C++, and D
您需要添加stdarg.h,然后使用va_list
,va_start
,va_arg
和va_end
,如维基百科文章中的示例所示。它比Java或C#更麻烦,因为C和C ++对varargs的内置支持有限。
答案 5 :(得分:1)
如果您不关心可移植性,可以使用this C99 code将gcc's statement expressions移植到C ++:
#include <cstdio>
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)不支持它们。
答案 6 :(得分:1)
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<count; j++)
tot+=va_arg(ap, double); //Requires the type to cast to. Increments ap to the next argument.
va_end(ap);
return tot/count;
}
这也可以写成:
double average(int count, void** params)
{
int j;
double tot = 0;
for (j=0; j<count; j++)
tot+=*(double*)params[j];
return tot/count;
}
现在就像这样使用它:
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 <process.h>
double average(int count, void** params)
{
int j;
double tot = 0;
for (j=0; j<count; j++)
tot+=*(double*)params[j];
return tot/count;
}
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;
}
<强>输出:强>
平均值是:2
按任意键继续。 。
答案 7 :(得分:1)
我在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 ...
}
}