I'm implementing a templated class Vect<std::size_t N>
, a vector of N double
. The general constructor takes a std::array<double, N> const&
array, but I would like for instance for N=2
to have a constructor taking 2 double
, to allow lighter instantiation.
I thought of a solution that works well (see below), but it feels a bit dirty. I've gone through many questions asked here and their answers, but I haven't quite found a solution that fits my problem nicely.
I'd also like to have an alias Vect2D
for Vect<2>
, either with a typedef
or anything else that does the job (for instance, my solution below).
Here is some of the code of my class Vect
:
template<std::size_t N> class Vect{
protected:
std::array<double,N> v;
public:
Vect(const std::array<double,N>& _v = {}): v(_v) {}
/* bunch of methods & operators */
};
and here is my solution for now:
class Vect2D : public Vect<2>{
public:
Vect2D(double x = 0, double y = 0): Vect({x,y}) {}
Vect2D(const Vect<2>& other): Vect(other){}
};
(I had to add the last line because while Vect2D
is a Vect<2>
, Vect<2>
is not a Vect2D
, so when I use operators between two Vect2D
, the returned object has type Vect<2>
so if needed I convert it back to Vect2D
with this last line, for instance if the return type of a function is Vect2D
, and what I return is the result of an operator between two Vect2D
. It does the job, but this is partially why I feel this solution is kinda dirty.)
I'd be grateful if anyone has a nice solution, otherwise it's not a big deal since my solution does what I want anyway.
What about avoiding the full class specialization and SFINAE enabling the two-double contructor only when N
is 2?
Something as
template <std::size_t M = N, std::enable_if_t<(M == 2), int> = 0>
Vect (double x = 0, double y = 0): v{x,y} {}
I'd also like to have an alias
Vect2D
forVect<2>
, either with atypedef
or anything else that does the job
What about using using
?
using Vect2D = Vect<2>;
The following is a full compiling example with external constructor implementation.
#include <array>
#include <type_traits>
template <std::size_t N>
class Vect
{
protected:
std::array<double, N> v;
public:
Vect (std::array<double, N> const & v0 = {});
template <std::size_t M = N, std::enable_if_t<(M == 2), int> = 0>
Vect (double x = 0, double y = 0);
};
template <std::size_t N>
Vect<N>::Vect (std::array<double, N> const & v0) : v{v0}
{ }
template <std::size_t N>
template <std::size_t M, std::enable_if_t<(M == 2), int>>
Vect<N>::Vect (double x, double y) : v{x,y}
{ }
// explicit deduction guide
Vect (double, double) -> Vect<2u>;
int main()
{
Vect<2u> v2{1.0, 2.0}; // compile
Vect v2bis{1.0, 2.0}; // compile as Vect<2> (thanks to the deduction guide)
// Vect<3u> v3{1.0, 2.0}; // compilation error (no matching constructor)
}