无法从 initializer_list 转换为我的类型,它具有模板可变参数构造函数

问题描述

所以,这并不是我必须做的事情,我只是在玩。我为任意数值类型和任意数量坐标的向量编写了一个 Vector 类。它用作 Vector<NumericType,[num of coords]>代码如下:

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

现在我要做的是确保上面声明的转换函数正常工作。使用思路是这样的:

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

这里的问题是在编译转换函数时,生成的新值以std::initializer_list<NewType> 的形式出现。出于某种原因,这不符合构造函数 Vector(NumTypes&&... vals) 的条件。现在我不想有一个初始化列表构造函数 - 预期参数的数量不是可变的,它必须是 Size 模板参数所说的。

那么如何解决这个问题呢?如何将 std::initializer_list 转换为 NumTypes&&... vals 是什么?

在这里我必须承认,我不准确知道我在做什么,我正在努力提高我的 C++ 知识。

解决方法

Convert 中,您有参数包 Is,您希望将其与 callbackvalues 结合使用。

参数包扩展“扩展为以逗号分隔的零个或多个模式列表”,因此这就是与问题中的值一起使用时会得到的结果:

Is...

0,1,2

values[Is]... => values[0],values[1],values[2]

1.4,2.5,3.6

callback(values[Is])... => callback(values[0]),callback(values[1]),callback(values[2])

1,3,4

并且你想像这样创建一个braced-init-list

{callback(values[0]),callback(values[2])}
// =>
{1,4}

所以:

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