bricklore
bricklore

Reputation: 4165

template member variable specialization

I have a template class with lots of functions and only want to specialize a few of them, while also adding a member variable.

Is that possible without the need to reimplement all the functions for the specialized class?


What I have:

template<class T> class Vector3
{
    union {
        T data[3];
        struct { T x, y, z; };
    };

    //a lot of functions

    T Length() { ... };
};

What I want to do:

template<> class Vector3<float>
{
    union {
        float data[3];
        struct { float x, y, z; };

        //new union member only for <float>!
        __m128 xmm;
    };

    float Length() {
        //special instructions for special case <float>
    };
};

As 95% of all functions stay exactly the same, I definitely don't want to reimplement them for every single specialization. How can I achieve that?

Upvotes: 5

Views: 2776

Answers (1)

Chris Beck
Chris Beck

Reputation: 16204

One thing you could do is make a helper template that generates a structure-with-union type that is the "core" of your type:

template <typename T>
struct Vector3_core {
  union {
    T data[3];
    struct { T x, y, z; };
  };

  T length() { ... }
};

and specialize it for float as desired:

template <>
struct Vector3_core<float> {
  union {
    float data[3];
    struct { float x, y, z; };
    __m128 xmm;
  };

  float Length() { ... }
};

Then you could write the main class using simple inheritance like:

template<class T> class Vector3 : public Vector3_core<T>
{
  // Need to pull anonymous-struct members into this class' scope
  using Vector3_core<T>::x;
  using Vector3_core<T>::y;
  using Vector3_core<T>::z;

  // All your functions...
};

Note that there is no virtual-dispatch going on here. Also, you don't need to make the inheritance public necessarily, you could make it private and forward the Length function publicly.

You could also go further and use full-blown CRTP if would be useful.

Here's a code sample on Coliru showing that the idea works at C++11 standard, at least.

http://coliru.stacked-crooked.com/a/ef10d0c574a5a040

Upvotes: 5

Related Questions