Поскольку 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>
Как бы я это сделал? Как мне получить имя такого шаблона класса и его аргументы в целом?