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)
Template parameters may have default arguments.
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.)
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.
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.
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>
{
....
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 { ... }
};
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();
}
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> { /* ... */ };
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With