我有一个类,封装了一个stl兼容的容器类型,它是唯一的类成员,并给出了很多向量数学函数,可以应用在这个向量上。
这个类有各种各样的构造函数,其中一个构造函数是接受一个初始化器列表。
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 告诉我 它可以被初始化为 聚合初始化 - 这似乎不是任何一种通常的构造函数。那么有没有办法为我的类创建一个构造函数,正确地将一个初始化的语法转发到一个叫做 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;
};
另一种解决方案是使用可变模板构造函数。
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;
};
或更短的 c++20:
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;
};