Давай разбирать код по порядку.
template <typename T>
struct NameOf {};
Тут у нас определяется общая форма шаблона
NameOf
. Определение это я сразу назову неправильным, потому что от этого шаблона можно инстанцировать тип и получить совершенно непонятную ошибку компиляции дальше. Должно быть так, чтобы тип из общей формы шаблона инстанцировать было нельзя.
В этом месте должно быть предварительное объявление шаблона.
#define DEF_TYPENAME(type) template <> \
struct NameOf<type> {\
static const char value[];\
};\
const char NameOf<type>::value[] = #type;
Тут у нас определен макрос препроцессора, который раскроется в частное инстанцирование шаблона
NameOf
для переданного типа. Тут я скажу только то, что можно сделать полностью иначе и макрос тут полностью не нужен.
DEF_TYPENAME(int)
DEF_TYPENAME(double)
DEF_TYPENAME(long double)
DEF_TYPENAME(float)
DEF_TYPENAME(char)
DEF_TYPENAME(long)
DEF_TYPENAME(unsigned)
DEF_TYPENAME(unsigned long)
Символ
;
все таки был бы более уместен в этом месте, т.к. сейчас код выглядит несвязной простыней без структуры. Сразу хочется сказать что тут синтаксическая ошибка, хоть на самом деле это и не так.
В общем смысле, в этом месте блок вызовов макроса будет замещен на блок частных инстанцирований шаблона
NameOf
.
template <typename T, typename ...types>
void printTypes(T)
{
std::cout << NameOf<T>::value << std::endl;
}
template <typename T, typename ...types>
void printTypes(T, types... t)
{
std::cout << NameOf<T>::value << ", ";
printTypes(t...);
}
В этом месте определено два шаблона функции с перегрузкой. Первый шаблон - от одного аргумента, второй - от переменного числа параметров шаблона. Такое определение дает две ветви вывода функции
printTypes
из шаблона. Я сейчас остановлюсь лишь на второй ветви вывода.
template <typename T, typename ...types>
void printTypes(T, types... t)
{
std::cout << NameOf<T>::value << ", ";
printTypes(t...);
}
Это - шаблон функции с переменным числом параметров шаблона (
Variadic template). Синтаксис
typename ...types
в объявлении шаблона говорит что типов ожидается от нуля и пока фантазия не кончится. Как пользоваться таким шаблонами - хорошо описано в документации по моей ссылке.
Суть же этой ветви вывода заключается в том, чтобы позволить пользователю вызывать функцию с произвольным набором аргументов. В своем теле функция работает как будто ее вызвали от одного (первого) аргумента и далее рекурсивно уходит в вызов только от хвоста оставшегося списка аргументов.
В следствии оптимизации, хвостовая рекурсия
развернется в плоскую последовательность обращений к
std::cout << NameOf<T>::value << std::endl;
.