【问题标题】:Using variable number of float arguments使用可变数量的浮点参数
【发布时间】:2018-04-28 10:57:18
【问题描述】:

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

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

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

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

我试过可变参数模板:

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

但 float 是非类型,所以我已经完成了:

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

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

Polynomial(size_t _degree, ...);

但这真的很不安全。

目前我正在使用:

Polynomial(std::vector<float>);

但这会强制调用如下:

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

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

谢谢!

【问题讨论】:

  • “但这迫使呼叫变得像”......这有什么问题?恕我直言,对于调用者来说,接受向量比接受可变参数要灵活得多
  • ^那个。如果用户输入任意系数会怎样?

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


【解决方案1】:

你可以使用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. };
}

【讨论】:

  • 为什么构造函数Polynomial p{ 1, 2, 3. }; 不需要()。只是问,我从来没有见过。
  • @alseether 这是统一初始化,它是在 C++11 中添加的。您可以在 C++ 参考中查找所有初始化规则,包括具有 initializer_list 构造函数的特性。
  • 谢谢,我会用@max66 解决方案检查差异。我想我会保留所有三种方法
【解决方案2】:

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

另一种方法(简单但有缺点)可能是使用缩小来确保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】:

回答你的问题

我想知道有没有好的方法来做到这一点

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

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

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

【讨论】:

    【解决方案4】:

    您可以使用递归模板参数处理。总体思路是使用私有方法,将第一个参数添加到coefficient 向量中,并使用其他参数进行递归,直到它们都被处理完:

    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...);
        }
    };
    

    【讨论】:

      【解决方案5】:

      你有很多选择。您可能想查看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&lt;float&gt;

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

      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.

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

      【讨论】:

        【解决方案6】:

        你的做法是一种“好方法”。想象一下调用者想要传递 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());
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-10-21
          相关资源
          最近更新 更多