Зачем нам нужна специализация шаблона для параметра template-template - PullRequest
1 голос
/ 03 июля 2019

Взять в качестве примера этот код для определения длины списка типов:

template <class... Types>
class type_list {};

template <class TypeList>
struct type_list_length;  // <---

template <template <class...> class type_list, class... Types>
struct type_list_length<TypeList<Types...>>
{
    static constexpr std::size_t value = sizeof...(Types);
};

Godbolt

Зачем нам нужно помеченное объявление?Я пытался скомпилировать код без него в нескольких компиляторах, но всегда получаю ошибки.

Ответы [ 2 ]

1 голос
/ 03 июля 2019

Но зачем вообще нужна специализация?

Поскольку вы используете class следующим образом

std::cout << type_list_length<type_list<int, long, long long>>::value;
// ...........................^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ <- template argument

или также

std::cout << type_list_length<std::tuple<int, long, long long>>::value;
// ...........................^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ <- template argumen

или аналогичным образом.

Обратите внимание на аргумент шаблона: в обоих случаях тип ; type_list<int, long, long long> в первом случае std::tuple<int, long, long long>.

То есть вы не можете объявить type_list_length как получающий тип шаблона-шаблона

template <template <class...> class type_list, class... Types>
struct type_list_length // <--- doesn't work
{
    static constexpr std::size_t value = sizeof...(Types);
};

потому что вы должны вызывать его, передавая параметр template-template, а затем переменный список шаблонов; Я имею в виду ... вы должны использовать его следующим образом

std::cout << type_list_length<type_list, int, long, long long>::value;
std::cout << type_list_length<std::tuple, int, long, long long>::value;

но, таким образом, вы теряете силу класса: извлекаете и считаете параметр шаблона параметра типа.

Итак, сначала нужно объявить type_list_length как получающий тип

template <typename> // no template parameter name needed here (not used)
struct type_list_length; 

, а затем объявить и определить специализацию в случае, если полученный тип является шаблоном-шаблоном с аргументами

template <template <typename...> class type_list, typename... Types>
struct type_list_length<TypeList<Types...>>
{ // ...................^^^^^^^^^^^^^^^^^^   the parameter is a type
    static constexpr std::size_t value = sizeof...(Types);
};
1 голос
/ 03 июля 2019

Короткий ответ заключается в том, что без основного шаблона мы не можем написать специализацию.

Более длинный ответ: как бы вы извлекли Types... из экземпляров шаблонного типа без специализации?Вы не можете.

Вот попытка:

template <template <class...> class type_list, class... Types>
struct type_list_length
{
    static constexpr std::size_t value = sizeof...(Types);
};

Мы можем сделать это:

type_list_length<type_list, int, double, float>::value

Но не это:

using MyListType = type_list<int, double, float>;
type_list_length<MyListType>::value;

Потому чтонаш шаблон ожидает параметр template-template и некоторые типы, поэтому мы вынуждены принять только один тип для соответствия MyListType:

template <class T>
struct type_list_length
{
    static constexpr std::size_t value = // ????;
};

Но теперь мы столкнулись с другой проблемой.Как мы назначаем value?Нам нужен какой-то способ для извлечения аргументов шаблона для MyListType или, по крайней мере, для счетчика.

Нам нужен способ для сопоставления одного типа и аргументов, для которых он шаблонизирован.Следовательно, нам нужно сопоставить только один тип И его параметры шаблона.

template <class TypeList>
struct type_list_length; 

template <template <class...> class type_list, class... Types>
struct type_list_length<TypeList<Types...>>
{
    static constexpr std::size_t value = sizeof...(Types);
};

Первый (неполный) тип - это наш основной шаблон.Это позволяет нам начать сопоставление одного типа, например MyListType.

Второй (полный) тип - это наша специализация.это позволяет нам сопоставлять один тип И, если это шаблонный тип, сопоставлять типы, используемые в качестве параметров шаблона для него.

Оставляя первый тип неполным, мы демонстрируем наше намерение ТОЛЬКО допустить, чтобы специализация была действительной.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...