поскольку typeid(T).name()
не возвращает понятное человеку имя типа, это нам мало поможет, если мы хотим напечатать имя аргументов шаблона в некоторый шаблон класса, особенно когда мы отлаживаем. Нам часто хочется написать это в отладке:
print<Args...>(cout); //dump the names of all types to stdout!
Поэтому я пишу утилиту pretty-print, которая дает мне имя шаблона класса. Ну, это легче понять с помощью некоторого примера использования:
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>
Как бы я это сделал? Как я могу получить имя такого шаблона класса и его аргументы в общем?
Мне жаль, что это «отрицательный ответ» (я поднимаю ваш вопрос), но боюсь, вы не сможете этого сделать. Даже с учетом только шаблонных классов, которые принимают однородные списки нетиповых параметров (например, 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...
и т. д.), но было бы невозможно охватить последовательности разнородных типов, не говоря уже о последовательностях смешанных аргументов.
Боюсь, нам придется подождать, пока C ++ поддержит рефлексию, чтобы достичь того, что вы ищете.
Других решений пока нет …