使用可变数量的浮点参数

时间:2017-11-15 09:27:42

标签: c++ c++11 templates variadic-templates

我正在尝试为我的struct Polynomial实现灵活的构造函数:

struct Polynomial
{
    std::vector<float> coefficients;
    size_t degree;
};

多项式的次数是可变的。 我想要的是有一个像

这样的构造函数
Polynomial(float... _coefficients);

我尝试过variadic模板:

template<float... Args>
Polynomial(Args... args);

但是浮动是一种非类型,所以我已经完成了:

template<typename... Args>
Polynomial(Args... args);

但是这允许我的系数是任何东西,而不是我想要的。 我知道我可以使用:

Polynomial(size_t _degree, ...);

但它确实不安全。

目前我正在使用:

Polynomial(std::vector<float>);

但是这迫使调用如下:

Polynomial P({f1, f2, f3}); // with fn floats

所以我想知道是否有一个很好的方法来做到这一点。

谢谢!

6 个答案:

答案 0 :(得分:12)

您可以使用initializer_list

#include <vector>
#include <initializer_list>

struct Polynomial {
    std::vector<float> coeffs;
    std::size_t degree;

    Polynomial(std::initializer_list<float> init)
        : coeffs{ init }, degree(init.size()) { }
};

int main() {
    Polynomial p{ 1, 2, 3. };
}

答案 1 :(得分:3)

回答你的问题

  

我想知道是否有一个很好的方法来做到这一点

是的,我认为你这样做的方式不仅仅是可以接受的。甚至你使用Polynomial P({f1, f2, f3});的语法也不是那么难看。

此外,使用std::vector与可变参数一样有效,对其他人来说更容易理解。

使用可变参数方法,您会发现难以强制收到的这些类型为float,但是std::vector可以控制它

答案 2 :(得分:3)

我认为你的方式(矢量参数,或更好的(恕我直言)初始化列表)是一个好方法。

另一种方式(简单但有缺点)可能是使用缩小来确保Args...float或类型可以缩小到float。像

这样的东西
struct Polinomial
 {
   std::vector<double>  v;
   std::size_t          degree;

   template <typename ... Args>
   Polinomial (Args const & ... args)
      : v { float{args}... }, degree { sizeof...(Args) }
    { }
 };

它很简单,有效,例如

Polinomial p { 2.3f, 3.5f, 6.7f };

但您的构造函数不接受整数或doublelong double值;所以

Polinomial p { 2.3f, 3.5f, 6.7 };
// ........................^^^  double, error

Polinomial p { 2.3f, 3.5f, 6 };
// ........................^  int, error

并且可能限制太多。

答案 3 :(得分:2)

您可以使用递归模板参数处理。一般的想法是使用一个私有方法,将第一个参数添加到struct Polynomial { template<class...Args> Polynomial(Args... coeffs) { init(coeffs...); degree = coefficients.size() - 1; } std::vector<float> coefficients; size_t degree; private: void init(float coeff) { coefficients.push_back(coeff); } template<class...Args> void init(float first, Args...others) { init(first); init(others...); } }; 向量并与其他参数一起递归,直到它们全部被处理完毕:

{{1}}

答案 4 :(得分:0)

你有很多选择。您可能希望查看std::vector的构造函数以获取灵感。例如,带有两个迭代器的模板化构造函数非常灵活:

template<typename T>
Polynomial(T begin, T end) : coefficients(begin, end), degree(coefficients.size()) {}

auto init = std::vector<float>{2.0, 1.0, 4.0};
Polynomial p2{init.begin(), init.end()};

或者你可以像Jodocus建议的那样std::initializer_list<float>

你可以有一个带有任何容器类型的模板化构造函数:

template<typename T>
Polynomial(T container) 
: coefficients(begin(container), end(container))
, degree(coefficients.size()) {}

auto init = std::vector<float>{2.0, 1.0, 4.0};
Polynomial p2{init};

Live demo

或者您可以提供不同构造函数的组合以满足不同的需求。

答案 5 :(得分:0)

你这样做是一种很好的方式&#34;。想象一下,调用者希望传递100个系数。如果您使用可变参数,则强制调用者执行以下操作:

float c1,c2,c3,....c100;
// init them
Polynomial P(c1, c2, c3,....,c100);

如果我要使用100个系数,我肯定会将它们存储在一个向量中,将它们传递给多项式会相当麻烦:

auto coeffs = std::vector<float>(100);
Polynomial P(coeffs[0],coeffs[1],....,coeffs[100]);

但是,如果您接受一个向量,则调用者可以毫无痛苦地执行这两个操作:

Polynomial P({c1,c2,c2});
Polynomial P(coeffs);

另一方面,使用std::vector但不允许使用不同的容器是一种任意限制。接下来更好的方法是接受迭代器,然后让调用者执行:

Polynomial P(coeffs.begin(),coeffs.end());