6

I want to write a math vector template. I have a class which accepts type and size as template argument, with a lot of math operation methods. Now I want to write specializations where Vector<3> for instance has x, y, z as members which refer to data[0..3] respectively.

The problem is that I don't know how to create a specialization which inherits everything from the default template without creating either a base class or writing everything twice.

What's the most efficient way to do this?

template<class Type, size_t Size>
class Vector {
    // stuff
};

template<class T>
class Vector<3,T>: public Vector {
    public:
        T &x, &y, &z;
        Vector(): Vector<>(), x(data[0]), y(data[1]), z(data[2]){}
        // and so on
};
weltensturm
  • 2,164
  • 16
  • 17

2 Answers2

7

Somehow you should be able to derive from default implementation, but you are specializing an instance, so how? it should be a non-specialized version that you can be able to derive from it. So that's simple:

// Add one extra argument to keep non-specialized version!
template<class Type, size_t Size, bool Temp = true>
class Vector {
    // stuff
};
// And now our specialized version derive from non-specialized version!
template<class T>
class Vector<T, 3, true>: public Vector<T, 3, false> {
    public:
        T &x, &y, &z;
        Vector(): Vector<>(), x(data[0]), y(data[1]), z(data[2]){}
        // and so on
};
BigBoss
  • 6,904
  • 2
  • 23
  • 38
  • While this works nicely, it seems a bit clunky (to me) to have an internal template parameter in an external interface. – Cameron Oct 16 '12 at 21:53
  • User never use this extra template parameter, of course you have another option that both specialized and default implementation derive from a base class that contain actual implementation! but in my opinion that's a bit harder than this technique! – BigBoss Oct 16 '12 at 21:55
  • @Cameron all class interfaces show private data members as well. Needed for size calculation, but still. I think this justifies it, since it is never needed from outside. – weltensturm Oct 16 '12 at 22:01
  • Okay, it does not work that easily. When I return a Vector in the base class it is type Vector<3,double,true> which means it is not compatible to Vector<3,double,false> (which the subclass is). I'll check if casting works. – weltensturm Oct 16 '12 at 22:18
  • @weltensturm You can create your own cast is just piece of cake! `Vector(Vector const& rhs)` and `Vector(Vector const& rhs)` – BigBoss Oct 16 '12 at 22:20
  • Excellent, was getting 'error: recursive type undefined'. Your fix, while I did not want an extra parameter solved it. Was heading the way of splitting the implementation to a unique base, but no need now! – Chris A Dec 29 '15 at 15:12
1

Consider making this in a little different way, but goals will be achieved, Add external interface - I mean standalone functions X(), Y(), Z():

template<class T, size_t S>
T& x(Vector<T, S>& obj, typename std::enable_if<(S>=1)>::type* = nullptr)
{
   return obj.data[0];
}

template<class T, size_t S>
T& y(Vector<T, S>& obj, typename std::enable_if<(S>=2)>::type* = nullptr)
{
   return obj.data[1];
}

template<class T, size_t S>
T& z(Vector<T, S>& obj, typename std::enable_if<(S>=3)>::type* = nullptr)
{
   return obj.data[2];
}

There is no big difference between:

 Vector<T, 3>& obj
 return obj.x();

And

 Vector<T, 3>& obj
 return x(obj);

As a bonus - this interface works for matching sizes.

BigBoss
  • 6,904
  • 2
  • 23
  • 38
PiotrNycz
  • 23,099
  • 7
  • 66
  • 112