C++ 函数中的参数数目未知
我有一个班级成员:C++ 函数中的参数数目未知,c++,argument-passing,variadic-functions,C++,Argument Passing,Variadic Functions,我有一个班级成员: 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); }
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);
}
我不知道将使用多少参数。我需要获取每个参数,并将其放入名为系数的向量中。我该怎么做?我理解,在这种情况下,while(argValue!=NULL)
语句是不正确的。例如,我不能使用此签名:
LineND::LineND(int numArgs, double a ...)
要像这样更改条件,请执行以下操作:
while(argValue != numArgs);
关键是我不能更改方法的签名。需要用另一种方式来解决这个问题。在C++中,变量的参数被严重地混淆了,并且有充分的理由。其中一个原因是无法知道列表的结束位置,因此如果无法更改函数的签名,则必须指定某种类型的sentinel值来指示列表的结束位置。如果这两件事都做不到,你就完了。在这种情况下,你无法确定代码中的参数数量。您必须让该函数的调用方将double
s的数量传递给您(我假设第一个a
参数不包含参数的数量)。例如:
然后情况就变了
while (a--) { ... }
在C++11中,可以使用两个更好的设备来传递未指定数量的双倍数
请注意,两者之间存在差异;THO在转发时出现了一些问题,即代码“> {…}/<代码>不是C++中的表达式。后者会导致代码膨胀,因为它会为参数类型的每个组合生成一个函数
在C++03中,您只能使用助手对象(如库提供的对象)来传递未知数量的参数。您应该重写该方法以获取std::initializer\u list
如果您不能这样做,并且不能添加count
参数,那么修复方法是采用一个终止参数列表的sentinel值,例如0.0
或NaN
(或在函数上下文中没有意义的任何值)
例如,采用可变数量指针的函数使用NULL
作为哨兵值;采用结构列表的函数采用0初始化的结构作为哨兵。这在C API中相当常见;参见此处给出的示例是execl(“/bin/sh”、“sh”、“-c”、“date”、(char*)NULL)代码>将参数列表的前两个参数设置为参数的实际计数。变量参数列表有几个缺点:
- 打电话的人可以传递他们想要的任何东西
- 如果传递了非POD对象,则调用未定义的行为
- 您不能依赖参数的数量(调用者可能会出错)
- 您将大量责任放在客户身上,您希望客户能够更轻松地使用库代码(实际示例:格式字符串bug/-errors)
与可变模板相比:
- 编译时列表大小已知
- 类型在编译时是已知的
- 你有责任做事情,而不是你的客户,这是应该做的
例如:
void pass_me_floats_impl (std::initializer_list<float> floats) {
...
}
他现在可以做到:
pass_me_floats ();
pass_me_floats (3.5f);
pass_me_floats (1f, 2f, 4f);
但他不能这样做:
pass_me_floats (4UL, std::string());
因为这将在pass\me_uufloats-function中发出编译错误
如果您至少需要,比如说,两个参数,那么就这样做:
template <typename ...ArgsT>
void pass_me_floats (float one, float two, ArgsT... rest) {}
模板
无效传递\我\浮动(浮动一,浮动二,ArgsT…rest){}
当然,如果你想让它成为一个完整的内联函数,你也可以
template <typename ...ArgsT>
void pass_me_floats (ArgsT... rest) {
std::array<float, sizeof...(ArgsT)> const floaties {rest...};
for (const auto f : floaties) {}
}
模板
无效通行证浮动(ArgsT…rest){
数组常量浮动{rest…};
对于(const auto f:floaties){}
}
Ok,因此您不能更改函数的签名。你能至少添加到类和函数体中吗?非常感谢你的详细解释。我不太确定我是否理解“{…}
不是表达式”。你是说类似的东西吗?编辑:OOP,它们有一个太老的G++:@ PrHeNeLe:我指的是通过(注意到警告实际上是一个C++ C++标准的错误而不会通过新的GCC)的东西:那个<代码> {…} /CODE只是一个用于初始化的特殊语法,而不是一个表达式本身(在C++ GROAMR)中。您无法方便地将其保存到变量中以备以后使用,也无法从中推断类型等。您的示例仅在初始化局部变量时使用最普通的初始化器列表,从而避免了所有问题。有关另一个不一致性,请参阅。
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) {}
}