C ++中函数中可变数量的参数
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1579719/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Variable number of parameters in function in C++
提问by AndreyAkinshin
How I can have variable number of parameters in my function in C++.
如何在我的 C++ 函数中使用可变数量的参数。
Analog in 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:
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);
}
回答by Stephan202
These are called Variadic functions. Wikipedia lists example code for C++.
这些称为可变参数函数。维基百科列出了 C++ 的示例代码。
To portably implement variadic functions in the C programming language, the standard stdarg.hheader file should be used. The older varargs.h header has been deprecated in favor of stdarg.h. In C++, the header file
cstdarg
should be used.To create a variadic function, an ellipsis (
...
) must be placed at the end of a parameter list. Inside the body of the function, a variable of typeva_list
must be defined. Then the macrosva_start(va_list, last fixed param)
,va_arg(va_list, cast type)
,va_end(va_list)
can be used. For example:
为了在 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 <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;
}
回答by rubenvb
The real C++ solution is variadic templates. You'll need a fairly recent compiler and enable C++11 support if needed.
真正的 C++ 解决方案是可变参数模板。您将需要一个相当新的编译器,并在需要时启用 C++11 支持。
Two ways to handle the "do the same thing with all function arguments" problem: recursively, and with an ugly (but very very Standards compliant) solution.
两种处理“对所有函数参数做同样的事情”问题的方法:递归和丑陋(但非常符合标准)的解决方案。
The recursive solutionlooks somewhat like this:
该递归解决方案看起来有点像这样:
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
It generates one symbol for each collection of arguments, and then one for each step into the recursion. This is suboptimal to say the least, so the awesome C++ people here at SOthought of a great trick abusing the side effect of a list initialization:
它为每个参数集合生成一个符号,然后为递归的每一步生成一个符号。至少可以说这是次优的,所以这里的优秀 C++ 人想到了一个滥用列表初始化副作用的绝妙技巧:
struct expand_type {
template<typename... T>
expand_type(T&&...) {}
};
template<typename... ArgTypes>
void print(ArgTypes... args)
{
expand_type{ 0, (std::cout << args, 0)... };
}
Code isn't generated for a million slightly different template instantiations, and as a bonus, you get preserved order of you function arguments. See the other answer for the nitty gritty details of this solution.
不会为一百万个略有不同的模板实例生成代码,作为奖励,您可以保留函数参数的顺序。有关此解决方案的详细信息,请参阅其他答案。
回答by Seb
In C++11 and later you can also use initializer lists.
在 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 } );
回答by GManNickG
Aside from the other answers, if you're just trying to pass an array of integers, why not:
除了其他答案,如果你只是想传递一个整数数组,为什么不:
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);
You can't call it in parameter, form, though. You'd have to use any of the variadic function listed in your answers. C++0x will allow variadic templates, which will make it type-safe, but for now it's basically memory and casting.
但是,您不能在参数、表单中调用它。您必须使用答案中列出的任何可变参数函数。C++0x 将允许可变参数模板,这将使其类型安全,但现在它基本上是内存和强制转换。
You could emulate some sort of variadic parameter->vector thing:
你可以模拟某种可变参数->向量的东西:
// 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
Usage:
用法:
func(gen_vec(1,2,3));
回答by Jesper
See Variadic functions in C, Objective-C, C++, and D
请参阅C、Objective-C、C++ 和 D 中的可变参数函数
You need to include stdarg.hand then use va_list
, va_start
, va_arg
and va_end
, as the example in the Wikipedia article shows. It's a bit more cumbersome than in Java or C#, because C and C++ have only limited built-in support for varargs.
您需要包括STDARG.H然后用va_list
,va_start
,va_arg
和va_end
,如维基百科文章显示的例子。它比 Java 或 C# 稍微麻烦一些,因为 C 和 C++ 对可变参数的内置支持有限。
回答by Christoph
If you don't care about portability, you could port this C99 codeto C++ using gcc's statement expressions:
如果您不关心可移植性,您可以使用gcc 的语句表达式将此 C99 代码移植到 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));
}
You could do something similar with C++0x' lambda expressions, but the gcc version I'm using (4.4.0) doesn't support them.
你可以用 C++0x 的 lambda 表达式做类似的事情,但我使用的 gcc 版本 (4.4.0) 不支持它们。
回答by Christoph
GManNickG and Christoph answers are good, but variadic functions allow you push in the ...parameter whatever you want, not only integers. If you willwant in the future, to push many variables and values of differenttypes into a function without using variadic function, because it is too difficult or too complicated for you, or you don't like the way to use it or you don't want to include the required headers to use it, then you always can use void**
parameter.
GManNickG 和 Christoph 的答案很好,但可变参数函数允许您根据需要推入...参数,而不仅仅是整数。如果你会在想未来,推动许多变量和值不同类型成函数,而无需使用可变参数函数,因为它太困难,太复杂了你,或者你不喜欢的方式来使用它,或者你不'不想包含使用它所需的头文件,那么你总是可以使用void**
参数。
For example, Stephan202 posted:
例如,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;
}
this can be also written as:
这也可以写成:
double average(int count, void** params)
{
int j;
double tot = 0;
for (j=0; j<count; j++)
tot+=*(double*)params[j];
return tot/count;
}
Now use it like this way:
现在像这样使用它:
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;
}
for full code:
完整代码:
#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;
}
OUTPUT:
输出:
Average is: 2
Press any key to continue . . .
平均值为:2
按任意键继续 。. .
回答by a_asiado
I do mine like this in c++ builder xe.xx:
我在 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 ...
}
}