Прекрасные типы и шаблон класса вместе со всеми его аргументами шаблона

Поскольку typeid(T).name() не возвращает понятное человеку имя типа, это не очень нам поможет, если мы хотим напечатать имя аргументов шаблона в каком-то шаблоне класса, особенно при отладке. Нам часто хочется написать это при отладке:

print<Args...>(cout); //dump the names of all types to stdout!

Итак, я пишу утилиту для красивой печати, которая дает мне имя шаблона класса. Ну, это легче понять с помощью некоторых примеров использования:

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>>

Внутри я использую шаблон класса с именем template_name, который возвращает мне "Y", когда я передаю ему Y<int> в качестве аргумента шаблона. Вот как он частично специализирован для каждого шаблона пользовательского класса.

#define DEFINE_TEMPLATE_NAME(template_type) \
template<typename ... Ts>\
struct template_name<template_type<Ts...>>\
{\
    static const char* name()\
    {\
        return #template_type;\
    }\
};

И пользователь должен использовать этот макрос для регистрации своего класса шаблона как:

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

Это работает, потому что специализация template_name<template_type<Ts...>> является шаблоном класса с переменным числом аргументов только для типов, что означает, что он вернет мне имя шаблона класса, если все параметры шаблона типы. Он также может печатать типы функций и типы функций-членов:

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)

См. здесь рабочий код с другими деталями. Это отлично работает до сих пор.

Но теперь я исправляю это и хочу добавить поддержку нетиповых аргументов шаблона, а также смешанных аргументов шаблона:

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>

Как бы я это сделал? Как мне получить имя такого шаблона класса и его аргументы в целом?


person Nawaz    schedule 30.12.2012    source источник
comment
У GCC есть деманглер, который печатает довольно полезные имена классов шаблонов...   -  person Kerrek SB    schedule 30.12.2012
comment
@KerrekSB: Да, но это не стандарт. Я хочу что-то, что работает везде.   -  person Nawaz    schedule 30.12.2012


Ответы (1)


Мне жаль, что это «отрицательный ответ» (я голосую за ваш вопрос), но боюсь, вы не можете этого сделать. Даже если рассматривать только классы шаблонов, которые принимают однородные списки нетиповых параметров (например, template<int, int>, template<char, char, char> и т. д.), вам потребуется такая специализация:

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

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

Эта специализация допустима, но бесполезна, потому что тип аргумента U никогда не может быть выведен. Вы можете определить специальные специализации для унифицированных списков литералов наиболее распространенных типов (int..., char... и т. д.), но все равно будет невозможно охватить последовательности разнородных типов, не говоря уже о последовательностях смешанных аргументов.

Боюсь, нам придется подождать, пока С++ поддержит отражение, чтобы добиться того, что вы ищете.

person Andy Prowl    schedule 30.12.2012