Matrefeytontias
Matrefeytontias

Reputation: 632

Add specialized methods to a class template without SFINAE

I'm trying to define a bunch of generic code in a class template, and then add some functionality that's specific to some template parameter values. In short :

// A vector of linear algebra
template <int n>
struct Vector
{
    // A bunch of functions not relying on a specific value for n
    float norm() { ... }
    float dot(const Vector& other) { ... }
private:
    float _data[n];
};

This is all well and good, but 3D vectors specifically have a 2-component cross product, while vectors in other dimensions don't (well, some do but that's not what this is about). I could use SFINAE to make it so a cross function is only defined for n = 3, however I would prefer being able to define all the functions that don't depend on a specific value of n together, and then implement the rest in independent template specializations.

When looking around, I've seen the idea of inheriting from the class template entertained, but then I don't want to have to redeclare a new type. Furthermore, this apparently does not work (somewhat expectedly) :

template <>
struct Vector<3> : public Vector<3> // error: invalid use of incomplete type ‘struct Vector<3>’
{
    Vector cross(const Vector& other) { ... }
};

To put it differently, I want to specialize my Vector class but keep all the functions already defined in the class template, only adding more.

Is there any alternative to SFINAE, or is it my only option ?

Upvotes: 0

Views: 49

Answers (2)

max66
max66

Reputation: 66200

Not sure to understand what you exactly want... but seems to me that you're looking for a sort of self-inheritance as follows

// common part
template <int N, bool = N==3>
struct Vect
 {
   float foo_1 () { return 1.0f; }

   float _data[N];
 };

// additional methods for N==3 only
template <int N>
struct Vect<N, true> : public Vect<N, false>
 {
   float foo_2 () { return 2.0f; }

   // other additional methods
 };

that you can use in this way

   Vect<1>  v1;
   Vect<3>  v3;

   v1.foo_1();
   // v1.foo_2();  compilation error

   v3.foo_1();
   v3.foo_2();  // compile

Upvotes: 0

super
super

Reputation: 12928

You can use a common template alias to pull in the additional functionality if a condition is met.

template <int n>
struct Vector_impl {
    // base implementation
}

struct Vector_3_impl : Vector_impl<3> {
    // n == 3 specific implementation
}

template <int n>
using Vector = std::conditional_t<n == 3, Vector_3_impl, Vector_impl<n>>;

Upvotes: 1

Related Questions