I'm trying to make a system of classes that are small objects, and the base class has a member that is a unique identifier that identifies the class:
class Shape
{
public:
unsigned char id;
};
template <typename T>
class Triangle : public Shape
{
T triangle_data;
};
template <typename T>
class Square : public Shape
{
T square_data;
};
template <typename T>
class ShapeBox : public Shape
{
T shapebox_data;
Shape * child_shape;
};
With the class identifier, I go through a vector of Shape * and switch on the id visible in the base class, then static cast for different behavior (to Triangle, Square, or ShapeBox and child shapes held in it respectively for the example class hierarchy)
I could turn on RTTI, but the space cost seems fairly large, especially when the type information can be implemented as a pointer and the object size might be no bigger than a couple of bytes. There may be millions of small objects, and I really only need static cast anyways.
Currently I can make type identifiers by using statics that are assigned values from a static monotonically incrementing counter:
class TypeID
{
static size_t counter;
public:
template<typename T>
static size_t value()
{
static size_t id = counter++;
return id;
}
};
size_t TypeID::counter = 1;
Ideally I want dense, unique type ID's that are available at compile time, so the compiler can perform well, like converting a switch on the type IDs into a constant time jump table, or at least a binary search tree rather than a linear time if/else chain for what might be a long list of type IDs...
I can use boilerplate at compile time to manually assign every type ID, or I can use object/function pointers from a similar type ID class. Boiler plate is guaranteed to be dense (because we assign it manually) and known at compile time, but it's unmaintainable for template types. Whenever you add a template type to a shape, you have to manually add a new type. The monotonic static counter is maintainable and dense, but unknown at compile time and so compile time optimizations aren't possible, and thread safety may be a concern. The function pointer ID is known at compile time and maintainable, but isn't dense and won't fit into a small id type like a char.
Is there any way to generate type IDs that are visible to the compiler at compile time, dense, and automatically assigned, perhaps using template metaprogramming counter or some preprocessor magic in C++11 or C++14? Or is this not possible until C++ has compile time reflection?
See Question&Answers more detail:
os