函数中的参数数量未知

Ser*_*iev 3 c++ variadic-functions argument-passing

我有班级成员:

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);
}
Run Code Online (Sandbox Code Playgroud)

我不知道将使用多少个参数.我需要将每个参数都放入调用的向量中coefficients.我该怎么办?我理解,while(argValue != NULL)在这种情况下声明不正确.我不能使用例如这个签名:

LineND::LineND(int numArgs, double a ...)
Run Code Online (Sandbox Code Playgroud)

改变这样的条件:

while(argValue != numArgs);
Run Code Online (Sandbox Code Playgroud)

关键是我无法改变方法的签名.需要另一种方法来解决这个问题.

Seb*_*ach 15

变量参数列表有几个缺点:

  • 来电者可以传递他们想要的一切.
  • 如果传递了非POD对象,则会召唤未定义的行为
  • 你不能依赖参数的数量(调用者可以犯错误)
  • 您对您的CLIENT负有很多责任,对您而言,您希望更轻松地使用库代码(实际示例:format-string-bugs/-errors)

与可变参数模板相比:

  • 编译时间列表大小是已知的
  • 类型在编译时是已知的
  • 你有责任,而不是你的客户,这应该是它应该的.

例:

void pass_me_floats_impl (std::initializer_list<float> floats) {
    ...
}
Run Code Online (Sandbox Code Playgroud)

您可以将它放入类声明的私有部分或某些详细的命名空间中.注意:pass_me_floats_impl()不必在标头中实现.

那么这里是您客户的好东西:

template <typename ...ArgsT>
void pass_me_floats (ArgsT ...floats) {
    pass_me_floats_impl ({floats...});
}
Run Code Online (Sandbox Code Playgroud)

他现在可以这样做:

pass_me_floats ();
pass_me_floats (3.5f);
pass_me_floats (1f, 2f, 4f);
Run Code Online (Sandbox Code Playgroud)

但他做不到:

pass_me_floats (4UL, std::string());
Run Code Online (Sandbox Code Playgroud)

因为那会在你的pass_me_floats函数中发出一个编译错误.

如果你至少需要2个参数,那么就这样做:

template <typename ...ArgsT>
void pass_me_floats (float one, float two, ArgsT... rest) {}
Run Code Online (Sandbox Code Playgroud)

当然,如果你想要一个完整的内联函数,你也可以

template <typename ...ArgsT>
void pass_me_floats (ArgsT... rest) {
    std::array<float, sizeof...(ArgsT)> const floaties {rest...};

    for (const auto f : floaties) {}
}
Run Code Online (Sandbox Code Playgroud)