【发布时间】:2021-02-15 11:48:50
【问题描述】:
入门:C++ base class constructor taking derived class as argument (?)
我有一个Vector 和一个Vector2D 课程。前者应该包含一个允许按元素进行类型转换的构造函数。派生类也应该允许它。在某些情况下,它已经可以工作了(参见下面的示例),但我认为缺少一些 SFINAE 魔法。
Vector
#include <array>
#include <type_traits>
namespace mu {
template<std::size_t N, typename T>
class Vector {
public:
// ...
template <typename... TArgs,
std::enable_if_t<sizeof...(TArgs) == N ||
(!std::is_base_of_v<Vector, TArgs> && ...), int> = 0>
Vector(TArgs... args) : data({args...}) {}
// this should always be called for type casting:
template <std::size_t Nn, typename Tt>
Vector(const Vector<Nn, Tt> &other) {
static_assert(N == Nn, "Vector size mismatch");
for (std::size_t i = 0; i < N; i++) {
data[i] = static_cast<T>(other[i]);
}
}
Vector(const Vector &other) = default; // copy constructor
protected:
std::array<T, N> data;
};
}
Vector2D
namespace mu {
template<typename T>
class Vector2D : public Vector<2,T> {
public:
using Vector<2, T>::Vector; // inherit base class constructors
Vector2D(const Vector<2, T>& other) : Vector<2, T>(other) {}
// Vector2D specific functions, e.g. rotation
//...
};
}
示例(它们都应该编译)
// Example 1 (compiles)
mu::Vector<2, int> a{1, 2};
mu::Vector<2, float> b{a};
// Example 2 (compiles)
mu::Vector<2, int> c{1, 2};
mu::Vector2D<float> d{c};
// Example 3 (doesn't compile)
mu::Vector2D<int> e{1, 2};
mu::Vector<2, float> f{e};
// Example 4 (doesn't compile)
mu::Vector2D<int> g{1, 2};
mu::Vector2D<float> h{g};
错误(示例 3 和 4)
.../vector.h:63:27: error: no matching constructor for initialization of 'std::array<float, 2UL>'
Vector(TArgs... args) : data_({args...}) {}
代码尝试调用错误的构造函数,而不是包含类型转换的构造函数。我已经尝试在 enable_if 术语中添加另一个约束,但到目前为止没有好的结果。
【问题讨论】:
-
template <std::size_t Nn, typename Tt> Vector(const Vector<Nn, Tt> &other)可以简单地为template <typename Tt> Vector(const Vector<N, Tt> &other)。 -
我添加了 Nn 作为模板参数,这样我就可以添加一个 static_assert 来提供更清晰的错误消息,如“未找到匹配的构造函数”或某事。否则
标签: c++ templates inheritance constructor sfinae