Use case:
Vector class (implementing some math) and a derived Vector2D classVector
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
//...
};
}
note: the actual classes contain a lot more but i condensed it down to the code that i think is most important here.
The problem is that i'm not able to implement a way such that a Vector can be constructed from a Vector2D, see code below. All other cases work fine.
// 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};
Of course the more general question would be if inheritance is the right way to structure these classes. But i'd like Vector2D to have all the functionality of Vector and also additional functions that the Vector does not have.
Your Vector class has two constructor: a template one (intended for values) and the default copy constructor.
Problem: the copy constructor is preferred but only if there is an exact match.
So, initializing b with a
mu::Vector<2, int> a{1, 2};
mu::Vector<2, int> b{a};
the copy constructor is preferred because a is an exact match
But, initializing h with g
mu::Vector2D<int> g{1, 2};
mu::Vector<2, int> h{g};
g can be converted to a mu::Vector<2, int> but isn't an exact match, so the template constructor is preferred but the template constructor is incompatible.
A possible solution: SFINAE disable the template constructor when the there is only one argument and the argument is derived from mu::Vector.
For example
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...}) {}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With