What you are trying to do is part of the definition of reflection, more specifically run time type information (RTTI), which gives code the ability to examine at itself at runtime, I took a good look into this a while back when trying to make a system which would serialise all member variables of a passed in type to a format such as { "varName"=<varValue> }
Unfortunately the simple answer is that C++ does not natively support reflection, and where it provides "similar" functionality (i.e. <type_traits>
and typeid()
) it leaves much to be desired. The best results will come from custom build steps which generate data you require, I decided against this approach so can't really help with the "how to" in this case, but these approaches are obviously limited in portability.
However the approach of template specialisation which you have already mentioned is a step towards the best implementation I've seen yet for C++ runtime reflection, which uses a combination of macros to generate class descriptors.
The MFC macros DECLARE_DYNAMIC and IMPLEMENT_DYNAMIC are all the pollution you need to create one of these descriptors for your class, which then add the functions IsKindOf()
, GetRuntimeClass()
, etc., the most useful often being GetRuntimeClass()
which returns a CRuntimeClass
.
To implement something similar you could use something along the lines of;
#define MakeClassDescriptor(classname) \
private: \
class classname ## Descriptor \
{ \
public: \
static const char* GetName() { return #classname; } \
}; \
public: \
typedef classname ## Descriptor ClassDescriptor;
class Test
{
public:
Test() {};
MakeClassDescriptor(Test);
};
Which would then allow you to access the name through Test::ClassDescriptor::GetName()
There's of course other approaches and your own specifications dictate how you can implement this, for an example of an approach where classes inherit from a templated RTTI class check out the article "Using Templates for Reflection in C++" written by Dominic Filion in the book Game Programming Gems 5