将初始化列表/聚合初始化转发给 std::array 成员

Forwarding intializer list / aggregate inialization to std::array member

我有一个 class 封装了一个 stl 兼容的容器类型,它是唯一的 class 成员,并提供了很多可以应用于该向量的向量数学函数。

这个class有多种构造函数,其中一种是采用初始化列表的构造函数:

template <class Type, class VectorType = std::vector<Type>>
class MathVector
{
public:
    using initializer_list = std::initializer_list<Type>;

    MathVector (initializer_list il) : vector(il) {}

    // many more constructors and member functions here

private:
    VectorType vector:
}

虽然像 MathVector<int> foo = { 1, 2, 3 } 这样的东西运行良好,但 MathVector<int, std::array<int, 3>> bar = { 1, 2, 3 } 无法在 clang 上编译并出现像

这样的错误
(86, 55) No matching constructor for initialization of 'std::__1::array<int, 3>'

std::vector<int> foo = { 1, 2, 3 }std::array<int, 3> bar = { 1, 2, 3 } 有效,所以我猜想尽管语法相同,但在这种情况下 std::array 并不是真正通过初始化列表构造的。当查看 std 库源时,我没有找到任何基于 std::array 构造函数的初始化列表,这种猜测变得更加强烈。此外,cppreference tells me that it can be initialized with aggregate-initialization——它甚至看起来都不是任何一种常见的构造函数。那么有没有一种方法可以为我的 class 创建一个构造函数,它可以将具有所需语法的初始化正确地转发给 std::array 成员?

使用标签调度:

template <typename T>
struct type_identity { using type = T; };

template <typename Type, typename VectorType = std::vector<Type>>
class MathVector
{
public:
    MathVector(std::initializer_list<Type> il)
        : MathVector(il, type_identity<VectorType>{}) {}

private:
    template <typename T>
    MathVector(std::initializer_list<Type> il, type_identity<T>)
        : vector(il) {}

    template <typename T, std::size_t N>
    MathVector(std::initializer_list<Type> il, type_identity<std::array<T, N>>)
        : MathVector(il, std::make_index_sequence<N>{}) {}

    template <std::size_t... Is>
    MathVector(std::initializer_list<Type> il, std::index_sequence<Is...>)
        : vector{ *(il.begin() + Is)... } {}

    VectorType vector;
};

DEMO


另一种解决方案是使用可变模板构造函数。

template <typename Type, typename VectorType = std::vector<Type>>
class MathVector
{
public:
    template <typename... Ts>
    MathVector(Ts&&... ts)
        : vector{ std::forward<Ts>(ts)... } {}

    MathVector(MathVector& rhs)
        : MathVector(const_cast<const MathVector&>(rhs)) {}

    MathVector(const MathVector& rhs)
        : vector(rhs.vector) {}

private:
    VectorType vector;
};

DEMO 2

更短:

template <typename Type, typename VectorType = std::vector<Type>>
class MathVector
{
public:
    MathVector(std::convertible_to<Type> auto&&... ts)
        : vector{ std::forward<decltype(ts)>(ts)... } {}

private:
    VectorType vector;
};

DEMO 3