Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mixing partial template specialization and default template parameters

I would like to create a generic vector class and create specializations for a few cases. Something like this (it does not compile, but hopefully communicates my intentions):

template<int dim, typename T = float>
class Vector
{
public:
    typedef Vector<dim, T> VecType;

    Vector() { /**/ }
    Vector(const VecType& other) { /**/ )
    Vector& operator=(const VecType& other) { /**/ }

    VecType operator+(const VecType& other) { /**/ }    
    VecType operator-(const VecType& other) { /**/ }    
    T operator*(const VecType& other) { /**/ }

private:
    std::array<T, dim> elements;
};

template<int dim, typename T>
class Vector<2>
{
public:
    T x() const { return elements[0]; }
    T y() const { return elements[1]; }
};

template<int dim, typename T>
class Vector<3>
{
public:
    T x() const { return elements[0]; }
    T y() const { return elements[1]; }
    T z() const { return elements[2]; }
};

In other words, I want the default type of the elements to be float and I want to have x() and y() accessor methods for the dim = 2 case, and x(), y() and z() for the dim = 3 case. I'm a little confused by the error messages:

vector.h:56:10: error: declaration of ‘int dim’

vector.h:6:10: error: shadows template parm ‘int dim’

(same for T).

How can I do this correctly? (if it's possible)

like image 742
Tamás Szelei Avatar asked Dec 27 '11 13:12

Tamás Szelei


People also ask

Can template parameters have default values?

Template parameters may have default arguments.

Can a template be a template parameter?

A template argument for a template template parameter is the name of a class template. When the compiler tries to find a template to match the template template argument, it only considers primary class templates. (A primary template is the template that is being specialized.)

Why does the need of template specialization arise?

It is possible in C++ to get a special behavior for a particular data type. This is called template specialization. Template allows us to define generic classes and generic functions and thus provide support for generic programming.

What is the role of parameter in a template?

A template parameter is a special kind of parameter that can be used to pass a type as argument: just like regular function parameters can be used to pass values to a function, template parameters allow to pass also types to a function.


2 Answers

1.

When partially specializing a template, only supply the template parameters that are actually a parameter. Since you've already fixed dim to be 2 or 3, there's no need to specify it again.

template<typename T>
class Vector<2, T>
{
   ....

2.

Specializing a class really means changing the whole declaration. Therefore, the members s of the generic Vector<dim, T> will not be available in the specialized Vector<2, T>. You could make the generic Vector<dim, T> as into an internal base class, and create a subclass just for specialization:

template<int dim, typename T>
class VectorImpl;

...

template<int dim, typename T = float>
class Vector : public VectorImpl<dim, T> {};

template<typename T>
class Vector<2, T> : public VectorImpl<2, T>
{
public:
   T x() const { ... }
};

3.

You don't need to define VecType! Inside a template, you could just use Vector. It will automatically be deduced to refer to the class with the right parameters.

The end result that compiles:

#include <array>

template<int dim, typename T>
class VectorImpl
{
public:
    //typedef Vector<dim, T> VecType;

    VectorImpl() {  }
    VectorImpl(const VectorImpl& other) {  }
    VectorImpl& operator=(const VectorImpl& other) { return *this; }

    VectorImpl operator+(const VectorImpl& other) { return *this; }
    VectorImpl operator-(const VectorImpl& other) { return *this; }
    T operator*(const VectorImpl& other) { return 0; }

protected:
    std::array<T, dim> elements;
};

template <int dim, typename T = float>
class Vector : public VectorImpl<dim, T> {};

template<typename T>
class Vector<2, T> : public VectorImpl<2, T>
{
public:
    T x() const { return this->elements[0]; }
    T y() const { return this->elements[1]; }
};

template<typename T>
class Vector<3, T> : public VectorImpl<2, T>
{
public:
    T x() const { return this->elements[0]; }
    T y() const { return this->elements[1]; }
    T z() const { return this->elements[2]; }
};

int main()
{
    Vector<2> v;
    Vector<3> vv;
    v + v;
    vv.z();
}
like image 113
kennytm Avatar answered Oct 11 '22 04:10

kennytm


The partial specialization should be something like this:

template <int Dim, typename T = float> class Vector; // primary

template <typename T> class Vector<2, T> { /* ... */ };
template <typename T> class Vector<3, T> { /* ... */ };
like image 33
Kerrek SB Avatar answered Oct 11 '22 04:10

Kerrek SB