Since typeid(T).name()
doesn't return human understandable name of the type, it doesn't help us much if we want to print the name of the template arguments to some class template, especially when we're debugging. We often feel like writing this in debugging:
print<Args...>(cout); //dump the names of all types to stdout!
So I'm writing pretty-print utility which gives me the name of the class template. Well, it is easier to understand it through some sample usage:
print<int>(cout); //prints int
print<int, double, char>(cout); //prints int, double, char
print<std::string>(cout); //prints std::basic_string<char, .. etc>
print<std::wstring>(cout); //prints std::basic_string<wchar_t, .. etc>
print<X<int,Y<int>>>(cout); //prints X<int, Y<int>>
Internally, I'm using a class template called template_name
which returns me "Y"
when I pass Y<int>
to it as template argument. Here is how it is partially specialized for each user class template.
#define DEFINE_TEMPLATE_NAME(template_type) \
template<typename ... Ts>\
struct template_name<template_type<Ts...>>\
{\
static const char* name()\
{\
return #template_type;\
}\
};
And the user is required to use this macro to register his template class as:
DEFINE_TEMPLATE_NAME(std::basic_string);
DEFINE_TEMPLATE_NAME(std::vector);
DEFINE_TEMPLATE_NAME(X); //X is a class template
DEFINE_TEMPLATE_NAME(Y); //Y is a class template
That works because the specialization template_name<template_type<Ts...>>
is a variadic class template on types only, which means it would return me the name of class template as long as all the template parameters are types. It is also able to print function-types and member-function-types as well:
typedef void fun(int,int);
//lets use snl::name() which returns name instead of printing!
std::cout << snl::name<fun>(); //prints : void(int,int)
std::cout << snl::name<fun*>(); //prints : void(*)(int,int)
Please see the working code here with other minute details. That works great so far.
But now I'm improving on this, and want to add support for non-types tempate arguments and mixed template arguments as well:
template<int...>
struct Z{};
//non-type template arguments : 1,2,3
snd::print<Z<1,2,3>>(cout); //should print Z<1,2,3>
//mixed template arguments : int, 100
snd::print<std::array<int,100>>(cout); //should print std::array<int,100>
How would I do that? How do I get the name of such class template and its arguments generically?