[英]C++ base class constructor taking derived class as argument (?)
用例:
Vector
类(实现一些数学)和一个派生的Vector2D
类 Vector
namespace mu {
template<std::size_t N, typename T>
class Vector {
public:
// ...
template <typename... TArgs>
Vector(TArgs... args) : data({args...}) {}
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
//...
};
}
注意:实际的类包含更多内容,但我将其浓缩为我认为在这里最重要的代码。
问题是我无法实现一种可以从Vector2D
构造Vector
的Vector2D
,请参阅下面的代码。 所有其他情况都可以正常工作。
// Example 1 (compiles)
mu::Vector<2, int> a{1, 2};
mu::Vector<2, int> b{a};
// Example 2 (compiles)
mu::Vector2D<int> c{1, 2};
mu::Vector2D<int> d{c};
// Example 3 (compiles)
mu::Vector<2, int> e{1, 2};
mu::Vector2D<int> f{e};
// Example 4 (doesn't compile) <-- how to get this to work?
mu::Vector2D<int> g{1, 2};
mu::Vector<2, int> h{g};
当然,更普遍的问题是继承是否是构建这些类的正确方法。 但是我希望Vector2D
具有Vector
所有功能以及Vector
没有的附加功能。
您的Vector
类有两个构造函数:一个模板(用于值)和默认的复制构造函数。
问题:复制构造函数是首选,但前提是存在完全匹配。
所以,用a
初始化b
mu::Vector<2, int> a{1, 2};
mu::Vector<2, int> b{a};
首选复制构造函数,因为a
是完全匹配的
但是,用g
初始化h
mu::Vector2D<int> g{1, 2};
mu::Vector<2, int> h{g};
g
可以转换为mu::Vector<2, int>
但不是完全匹配,因此模板构造函数是首选,但模板构造函数不兼容。
一种可能的解决方案:当只有一个参数并且该参数从mu::Vector
派生时,SFINAE 禁用模板构造函数。
例如
template <typename... TArgs,
typename std::enable_if_t<sizeof...(TArgs) == N
or (not std::is_base_of_v<Vector, TArgs> && ...), int> = 0>
Vector(TArgs const & ... args) : data({args...}) {}
撇开继承对这个特定任务的适用性不谈,失败的直接原因是template <typename... TArgs>
构造函数。 它将拦截每个不是副本的构造——并且从派生类对象构造不是副本。 这是因为从 Derived 到 Base 的转换是一种转换,而模板构造函数不需要转换,所以是更好的匹配。
如果参数适合构造std::array
成员,您希望将全部构造函数限制为仅包含在重载决议中。 这是 SFINAE 的标准应用程序。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.