我有班级成员:
LineND::LineND(double a ...)
{
coefficients.push_back(a);
va_list arguments;
va_start(arguments, a);
double argValue;
do
{
argValue = va_arg(arguments, double);
coefficients.push_back(argValue);
}while(argValue != NULL); // THIS IS A PROBLEM POINT!
va_end(arguments);
}
我不知道将使用多少个参数。我需要将每个参数都放入名为coefficients
的向量中。我该怎么办?我理解,在这种情况下,while(argValue != NULL)
语句不正确。我不能使用例如这个签名:
LineND::LineND(int numArgs, double a ...)
改变这样的条件:
while(argValue != numArgs);
关键是我无法改变方法的签名。需要以另一种方式解决这个问题。
答案 0 :(得分:15)
变量参数列表有几个缺点:
与可变参数模板相比:
示例:
void pass_me_floats_impl (std::initializer_list<float> floats) {
...
}
您可以将其放入类声明的私有部分或某些详细命名空间中。注意:pass_me_floats_impl()
不必在标题中实现。
然后这是给你的客户好的东西:
template <typename ...ArgsT>
void pass_me_floats (ArgsT ...floats) {
pass_me_floats_impl ({floats...});
}
他现在可以做到:
pass_me_floats ();
pass_me_floats (3.5f);
pass_me_floats (1f, 2f, 4f);
但他做不到:
pass_me_floats (4UL, std::string());
因为这会在你的pass_me_floats函数中发出编译错误。
如果你需要至少,比方说2个参数,那么就这样做:
template <typename ...ArgsT>
void pass_me_floats (float one, float two, ArgsT... rest) {}
当然,如果你想要一个完整的内联函数,你也可以
template <typename ...ArgsT>
void pass_me_floats (ArgsT... rest) {
std::array<float, sizeof...(ArgsT)> const floaties {rest...};
for (const auto f : floaties) {}
}
答案 1 :(得分:3)
可变参数在C ++中非常不受欢迎,并且有充分的理由。其中一个原因是无法知道列表的结束位置,因此如果您无法更改函数的签名,则必须指示某种类型的标记值以指示列表的位置结束。如果你不能做其中任何一件事,那你就搞砸了。
答案 2 :(得分:1)
在这种情况下,您无法确定代码中的参数数量。你必须让这个函数的调用者传递给你double
的数量(我假设第一个a
参数不包含参数的数量)。例如:
LineND::LineND(unsigned count, ...)
{
va_list arguments;
va_start(arguments, a);
,条件变为
while (a--) { ... }
在C ++ 11中,您可以使用两个更好的设备来传递未指定数量的双精度数。
vector
and initializing it with an initializer-list 请注意,两者之间存在差异;因为{...}
不是C ++中的表达式而导致转发时,前者有一些问题。后者会导致代码膨胀,因为它为每个参数类型组合生成一个函数。
在C ++ 03中,您只能使用辅助对象(例如Boost.Assignment库提供的辅助对象)来传递未知数量的参数。
答案 3 :(得分:1)
您应该重写方法以取std::initializer_list<double>
。
如果您不能这样做,并且无法添加count
参数,则修复方法是采用终止参数列表的 sentinel 值,例如0.0
或NaN
(或任何在您的函数上下文中没有意义的值)。
例如,采用可变数量指针的函数使用NULL
作为sentinel值;采用结构列表的函数将0初始化结构作为标记。这在C API中相当常见;请参阅http://c-faq.com/varargs/nargs.html,其中给出的示例为execl("/bin/sh", "sh", "-c", "date", (char *)NULL);
答案 4 :(得分:0)
使参数列表的第一个双精度为实际的参数计数。