Dave
Dave

Reputation: 1334

C++ templates - partial specialisation of member function

I am trying to specialise some geometrical functions depending on 2D or 3D, specified by a template parameter. Best if I include some (very broken) code for a toy version of the problem:

template <typename T, int d>
class Point
{
public:
    int x;
    int y;
    int z;

    T add ()
    {
        return T(0);
    }

    template <>
    T add <T, 2> ()
    {
        return x + y;
    }

    template <>
    T add <T, 3> ()
    {
        return x + y + z;
    }
};

This code fails miserably to compile. I've tried lots of different combinations of template parameter formats and class definitions, and cannot find a way to do function specialisation on 'd' whilst leaving the 'T' general.

In my actual solution I'm trying to calculate things like gradients, curvature, interpolation, etc, specialised for 2D or 3D cases. Some things, like gradient calculations, can simply use the 'd' parameter to limit for-loop iterations. Others, like interpolation, require a separate function for 2D and 3D.

Any hints much appreciated!

Upvotes: 3

Views: 947

Answers (2)

Sarfaraz Nawaz
Sarfaraz Nawaz

Reputation: 361762

I would suggest this solution:

template <typename T, int d> 
class Point : public Point<T, d-1>
{
   typedef Point<T, d-1> base;
   T m_value;
public:
    T add()
    {
        return m_value + base::add();
    }   

    //another method which returns you the point value
    template<int N>
    T get()
    {
       return N==d ? m_value : base::get<N>();
    }
};

template <typename T>
class Point<T,0>
{
protected:
    T add()
    {
        return T(); //default value which is zero for all builtin types
    }
    template<int N>
    T get() { return T(); }

};

Using this solution you can have as many points as you want, but greater than zero.

Point<int,1> p1;  //contains 1 point
Point<int,2> p2;  //contains 2 points
Point<int,3> p3;  //contains 3 points
Point<int,4> p4;  //contains 4 points
Point<int,5> p5;  //contains 5 points

auto x1 = p5.get<1>(); //get first point
auto x3 = p5.get<3>(); //get third point
auto x4 = p5.get<4>(); //get fourth point

Or have these typedefs for convenience:

typedef Point<int,2> Point2D;
typedef Point<int,3> Point3D;

//then use them
Point2D p2d;
Point3D p3d;

Well that is just a basic idea which can be further enhanced, supporting many useful functionalities. I just wrote get<> to demonstrate one functionality which seems to be useful.

Upvotes: 7

Vaughn Cato
Vaughn Cato

Reputation: 64308

Here is how your example might work. You first declare your primary template:

template <typename T, int d> class Point;

There is no need to define it, because you don't have a general implementation.

Next, you create partial specializations for different numbers of dimensions, but your partial specializations will still have type T as a template parameter:

template <typename T>
class Point<T,2>
{
public:
    T x;
    T y;

    T add()
    {
        return x + y;
    }
};

template <typename T>
class Point<T,3>
{
public:
    T x;
    T y;
    T z;

    T add()
    {
        return x + y + z;
    }
};

Upvotes: 5

Related Questions