Wednesday, June 4, 2008

Generating a typeID from a type using templates

Ever want to generate a unique typeID from a type? You can by using templates!

Eventually we will want something of the form:
ASSERT(typeID(TypeA) != typeID(TypeB))

But first lets start with something a little simpler:

ASSERT(typeID<float>() == typeID<float>()) and
ASSERT(typeID<char>() != typeID<int>())


The trick here is to take an address of a singleton pointer of a specific type. The pointer doesn't actually point to anything, it's just there to generate a unique number.

Let's define a template function:

template<typename T>
size_t typeID() {
static const T* type_id;
return reinterpret_cast<size_t>(&type_id);
}

Let's see what this is doing. First only one function will used after the C++ source has been linked. Our singleton is the static const T* type_id pointer. The location of this pointer in memory is what is important since it is unique. Uniqueness is important since we can use it test for equality. Equal types will produce equal type ids'.

To make this slightly more useful, we are going to want to deduce the type id automatically by the type of an input value. So let's overload the typeID function with one that deduces the type based on the argument.

template<typename T>
size_t typeID(const T& t) {
return typeID<T>();
}

Now this allows us to do things like:

int a;
bool b;

ASSERT(typeID(a) != typeID(b));

Note that what this solution does not due is determine the subtype from a base type reference. For that you would want to store the typeID during construction of the object. Also, because the typeID() function is created by the compiler, libraries that are not linked together (aka dynamic linked libraries) will produce different typeid's. The type id can (and probably will) change whenever the project has been rebuilt.

No comments: