Cannot convert from initializer_list to my type, which has templated variadic constructor

So, this isn’t really something I have to do, I was just playing around. I wrote a Vector class for vectors of any numeric type and any number of coordinates. It is used as Vector<NumericType, [num of coords]>. Here is the code:

#include <array>
#include <functional>

namespace World {

template <typename NumType, unsigned char Size>
class Vector
{
public:
  using CoordType = NumType;


  template<typename... NumTypes>
  constexpr Vector(NumTypes&&... vals) : values{ std::forward<NumTypes>(vals)... }
  {
    static_assert(sizeof...(NumTypes) == Size, "You must provide N arguments.");
  }

  Vector(const std::array<NumType, Size>& values) : values(values) {}
  Vector(const std::array<NumType, Size>&& values) : values(std::move(values)) {}

  const NumType& operator[](size_t offset) const { return values[offset]; }
  NumType& operator[](size_t offset) { return values[offset]; }

  //! Converts all values to new given type
  template <typename NewType>
  constexpr Vector<NewType, Size> Convert() const { return Convert<NewType>(std::make_index_sequence<Size>{}); }
  //! Converts all values via the conversion function
  template <typename NewType>
  Vector<NewType, Size> Convert(const std::function<NewType(NumType)>& callback) const { return Convert<NewType>(std::make_index_sequence<Size>{}, callback); }

  std::array<NumType, Size> values;

private:
  //! Converts all values to new given type
  template <typename NewType, std::size_t ... Is>
  constexpr Vector<NewType, Size> Convert(std::index_sequence<Is...>) const { return { { static_cast<NewType>(values[Is])}... }; }
  //! Converts all values via the conversion function
  template <typename NewType, std::size_t ... Is>
  Vector<NewType, Size> Convert(std::index_sequence<Is...>, const std::function<NewType(NumType)>& callback) const { return { { callback(values[Is])}... } ; }
};

Now what I am trying to do now is to make sure that the conversion function declared above is working. The idea of usage is this:

using namespace World;
using Vector3D = Vector<double, 3>;
using Vector3Int = Vector<int, 3>;

#include <cmath>

int main()
{
  const Vector3D src{ 1.4, 2.5, 3.6 };
  const Vector3Int target = src.Convert<int>([](double val) { return (int)std::round(val); });
  return 0;
}

The issue here is that when the conversion function is compiled, the resulting new values appear in the form of std::initializer_list<NewType>. For some reason, this doesn’t qualify for the constructor Vector(NumTypes&&... vals). Now I do not want to have an initializer list constructor – the number of expected arguments is not variable, it must be whatever the Size template parameter says.

So how to get around this? How can I convert std::initializer_list to whatever NumTypes&&... vals is?

I must admit here I do not precisely know what I’m doing, I am trying to improve my C++ knowledge.

Source: Windows Questions C++

LEAVE A COMMENT