C++ template aliasing
Return to home page
Comments Loading...
2010-09-14

Recently I have been working on some C++ classes which make heavy use of templates. In particular there are two classes Vector, T, N and Matrix<T, M, N=M> where you specify the type of the elements and the number of elements for both. Examples of how you would use these are:


Vector<double, 3> myVector(1, 2, 3);

Matrix<float, 3> myIdentityMatrix;


As you can imagine, typing out that full declaration everywhere gets a little tiresome after a while. What I really wanted was a way to alias Vector3 to mean Vector<double, 3> yet at the same time be able to easily do Vector3<float>.

The most logical thing you might try and do is to template the typedef, eg:


template <typename T=double> typedef Vector<T, 3> Vector3;


However, you'll quickly discover that this is an unimplemented feature of C++0x. So what can you do instead? The simplest thing that came to mind at first was to make a subclass:


template <typename T=double> class Vector2 : public Vector<T, 2> {

Vector2 (void) : Vector () {}

Vector2 (T x, T y) : Vector (x, y) {}

};


The obvious problem here is that you have to re-implement the constructors and destructors each time you do this and if new constructors are added, they have to be added to the subclasses as well.

A thread on stack overflow had a different solution to the problem. While C++ doesn't let you template typedefs, it does let you template structs, which can contain typedefs:


template <typename T=double> struct Vector2 {

typedef Vector<T, 2> type;

};


This approach is a true alias, however it requires you to declare your variables like this:

Vector2<>::type myVector;

That's almost as much typing as you would be doing before - albeit without having to redeclare the types and dimensions every time. As I discussed this problem with a friend, he suggested that I template a namespace and then import the types with using, but it turns out that the following is invalid:

using LinearMath::Vectors<>;

You cannot have a template-id in a using-declaration. It introduces ambiguities in to the namespace. But this got me thinking about importing stuff in to your namespace and I realized I could actually do it using subclassing. Since all my code was generally in classes already, it was a simple matter of creating a class that I could inherit from.


template <typename T=double> class Vectors {

public:

typedef Vector<T, 2> Vector2;

};


class MyClass : Vectors<> {

Vector2 myVector;

};


What's particularly neat about this is that all the code in my class gets to uniformly use the same vector types and matrix types where appropriate - and they are true aliases, so two compatible types blend together without issue.

This goes to demonstrate the already well known fact that C++ is a very unpolished language with lots of rough edges. Templates exist, but they are not uniform across the language and there are many holes you can easily fall in to. Without namespace templates, typedef templates, using templates.. I was luckily able to find a solution using multiple inheritance.