Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pretty-print types and class template along with all its template arguments

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?

like image 384
Nawaz Avatar asked Dec 30 '12 15:12

Nawaz


People also ask

What is template and its types?

A template is a C++ programming feature that permits function and class operations with generic types, which allows functionality with different data types without rewriting entire code blocks for each type.

What are template arguments?

In C++ this can be achieved using template parameters. A template parameter is a special kind of parameter that can be used to pass a type as argument: just like regular function parameters can be used to pass values to a function, template parameters allow to pass also types to a function.

How many template arguments are there?

1) A template template parameter with an optional name. 2) A template template parameter with an optional name and a default. 3) A template template parameter pack with an optional name.


1 Answers

I'm sorry this is a "negative answer" (I am upvoting your question), but I'm afraid you cannot do that. Even considering only template classes which accept homogeneous lists of non-type parameters (e.g. template<int, int>, template<char, char, char>, etc.), you would need a specialization of this kind:

template<typename T>
struct single_type
{
    // ...
};

template<typename U, template<U...> class C, U... Us>
struct single_type<C<Us...>>
{
    // ...
};

This specialization is legal but useless, because argument type U can never be deduced. You may define dedicated specializations for uniform lists of literals of the most common types (int..., char..., etc.), but it would still be impossible to cover sequences of heterogeneous types, let alone sequences of mixed arguments.

I'm afraid we'll have to wait for C++ to support reflection in order to achieve what you're looking for.

like image 115
Andy Prowl Avatar answered Oct 14 '22 10:10

Andy Prowl