lundi 20 juillet 2015

Variadic Templated Factory Function

I'm looking to create a "factory function" for a mathematical Vector class that is templated for size and type. Here is the declaration of the class:

template<class T, std::size_t n>
class Vector {
  std::array<T, n> elements;

public:
  Vector();
  explicit Vector(std::array<T, n>& elements_);
  explicit Vector(const Vector<T, n>& v);
  explicit Vector(Vector<T, n>&& v);
  ~Vector() noexcept = default;
  Vector<T, n>& operator =(const Vector<T, n>& v);
  Vector<T, n>& operator =(Vector<T, n>&& v);
  T& operator [](std::size_t i);
};

The idea is that it is annoying to have to first create an array and then make a vector from it. I want a variadic function called make_vector that takes n arguments of the same type T and returns a vector of that type and size. Here is my attempt:

  template<class T, class... Ts>
  Vector<T, sizeof...(Ts) + 1> make_vector(T v1, Ts... args) {
    const std::size_t sz = sizeof...(Ts) + 1;
    std::array<T, sz> vals = {v1, args...};
    return Vector<T, sz>{vals};
  }

However, I get the following bewildering errors:

In file included from main.cpp:6:
In file included from ./oglmath.hpp:3:
In file included from ./vector.hpp:79:
./vector.tpp:14:31: warning: suggest braces around initialization of subobject
      [-Wmissing-braces]
    std::array<T, sz> vals = {v1, args...};
                              ^~~~~~~~
                              {       }
main.cpp:32:17: note: in instantiation of function template specialization
      'ogl::make_vector<float, float, float>' requested here
  vertices[0] = make_vector(-1.0f, -1.0f, 0.0f);
                ^
In file included from main.cpp:6:
In file included from ./oglmath.hpp:3:
In file included from ./vector.hpp:79:
./vector.tpp:15:12: error: no matching constructor for initialization of 'Vector<float,
      sizeof...(Ts) + 1>'
    return Vector<T, sz>{vals};
           ^~~~~~~~~~~~~~~~~~~
./vector.hpp:13:5: note: candidate constructor not viable: requires 0 arguments, but 1
      was provided
    Vector();
    ^
In file included from main.cpp:6:
In file included from ./oglmath.hpp:3:
In file included from ./vector.hpp:79:
./vector.tpp:42:12: error: non-const lvalue reference to type 'Vector<[2 * ...]>' cannot
      bind to a temporary of type 'Vector<[2 * ...]>'
    return Vector<T, n>(v);
           ^~~~~~~~~~~~~~~
main.cpp:32:15: note: in instantiation of member function 'ogl::Vector<float,
      3>::operator=' requested here
  vertices[0] = make_vector(-1.0f, -1.0f, 0.0f);
              ^
1 warning and 2 errors generated.

Really? The only constructor it can find is the trivial one? What's going on!? I totally expected this to fail in a weird way if I tried to use different types in my Ts, but I was careful to make them all floats! Also, why is it getting angry at my initialization of my std::array? I tried adding the bracers, and it errored instead of warned.

Aucun commentaire:

Enregistrer un commentaire