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

поскольку 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>

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

12

Решение

Мне жаль, что это «отрицательный ответ» (я поднимаю ваш вопрос), но боюсь, вы не сможете этого сделать. Даже с учетом только шаблонных классов, которые принимают однородные списки нетиповых параметров (например, 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 ++ поддержит рефлексию, чтобы достичь того, что вы ищете.

6

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]