Рекурсивный шаблон Loki MakeTypelist сбивает меня с толку

#c

#c

Вопрос:

Я изучаю исходный код loki. ниже MakeTypelist приведено то, что меня смущает.

 class NullType {};
template <class T, class U>

struct Typelist
{
    typedef T Head;
     typedef U Tail;
};
template
<
typename T1  = NullType, typename T2  = NullType, typename T3  = NullType,
typename T4  = NullType, typename T5  = NullType, typename T6  = NullType,
typename T7  = NullType, typename T8  = NullType, typename T9  = NullType,
typename T10 = NullType, typename T11 = NullType, typename T12 = NullType,
typename T13 = NullType, typename T14 = NullType, typename T15 = NullType,
typename T16 = NullType, typename T17 = NullType, typename T18 = NullType
 > 
struct MakeTypelist
{
private:
 typedef typename MakeTypelist
 <
  T2 , T3 , T4 , 
  T5 , T6 , T7 , 
  T8 , T9 , T10, 
  T11, T12, T13,
  T14, T15, T16, 
  T17, T18
 >
  ::Result TailResu<

public:
  typedef Typelist<T1, TailResult> Resu<
};

template<>
struct MakeTypelist<>
{
  typedef NullType Resu<
};

using MyType=MakeTypeList<int, unsigned int, long, unsigned long, float>
  

Как завершается рекурсивный шаблон?

он не может соответствовать версии пустого типа MakeTypelist , в конце концов, он будет соответствовать MakeTypelist<NullType, NullType, NullType, NullType .....> ?

Комментарии:

1. Да, я думаю, вы правы, потому template<> struct MakeTypelist<> ... что все равно будете использовать аргументы шаблона по умолчанию NullType , так что это эквивалентно template<> struct MakeTypelist<NullType, NullType, ...> . Однако я не могу найти документацию, подтверждающую это, поэтому я не публикую ответ 🙂

2. У Loki есть тест, и код правильный.

3. Обратите внимание, что C 11 и шаблон variadic заменяют TypeList .

Ответ №1:

Рекурсивный шаблон завершится из-за template<> struct MakeTypelist<> определения специализации, которая возвращает NullType значение Result .

Эта специализация полностью соответствует следующему варианту кода

 template<>
struct MakeTypelist<NullType, NullType, NullType, NullType, ..... /* ... 18 Times ... */>
// .......
  

Потому что, если не предоставлены все или ни один параметр шаблона, то все непредоставленные параметры шаблона считаются равными значениям по умолчанию, т.Е. = NullType (См. Определение основного шаблона, в нем есть все 18 аргументов-типов, имеющих значение по умолчанию = NullType ).

Этот выбор аргументов по умолчанию для тех параметров шаблона, которые не предоставлены, имеет ту же логику, что и при использовании функций с аргументами по умолчанию, например, если у вас есть функция like void f(int a = 0, int b = 0) , вы можете вызвать ее тремя разными способами f() , f(0) f(0, 0) и все они дадут одинаковые результаты. И те аргументы функции, которые не указаны, будут приняты равными значениям по умолчанию. То же самое здесь в специализации шаблона — если вы не предоставляете никаких аргументов, т.е. Не пишете struct MakeTuplelist<> , то все 18 типов аргументов будут считаться NullType , потому что все 18 аргументов имеют значения по умолчанию = NullType , такое же поведение, как в функции с аргументами по умолчанию, приведенными выше. Пример.

Также в специализации вы можете указать только некоторые аргументы шаблона, остальные будут считаться равными значениям по умолчанию, например template<> struct MakeTypelist<int, bool> , специализация будет полностью совпадать со специализацией template<> struct MakeTypelist<int, bool, NullType, NullType, ...... /* 16 NullTypes */> .

И рекурсия завершается, потому что самый последний хвост равен MakeTypelist<NullType, NullType, NullType, .....> , который соответствует специализированной версии MakeTypelist , которая сокращает рекурсию, предоставляя NullType значение для Result .

Попробуйте онлайн!

PS. То же поведение по умолчанию применяется не только к специализации шаблона, но и к использованию, вы можете использовать шаблон как typedef MakeTypelist<> T; или typedef MakeTypelist<int, bool> T; в обоих случаях остальные 18 аргументов-типов шаблона станут равными значениям по умолчанию = NullType .

Комментарии:

1. «template<> struct MakeTypeList<>» равно «template <> struct MakeTypeList<NullType, NullType. ,,,,,>», я не мог понять, есть ли у C правило для этого?

2. @yuandaxing Да, точно, если некоторые аргументы шаблона не указаны, как здесь struct MakeTypeList<> , где аргументы не указаны, то аргументы шаблона считаются равными значениям по умолчанию, т.Е. Значениям = NullType , указанным в определении основного шаблона. Таким образом, в принципе, вы можете либо написать специализацию шаблона struct MakeTypeList<NullType, NullType. ,,,,,> , либо MakeTypeList<> оба дадут одинаковый результат! Или вы можете просто предоставить 1 или 2 аргумента, подобных этому struct MakeTypeList<NullType, NullType> , остальное берется из значений по умолчанию, а значения по умолчанию = NullType .

3. @yuandaxing Это то же самое, что вызов функции с аргументами по умолчанию, если ваша функция определена как void f(int a, int b = 12, int c = 34) , то вы можете вызвать ее как f(8) или f(8, 12) или f(8, 12, 34) , и все они будут давать одинаковый результат, если вы предоставляете значения, равные аргументам по умолчанию, те значения, которые не указаны, считаются равными значениям по умолчанию b для and c .

4. отличное объяснение

5. @yuandaxing Также вы не ограничены предоставлением ни одного или всех аргументов, вы также можете предоставить только некоторые аргументы, например template<> struct MakeTypelist<int, bool> , специализация будет полностью совпадать со специализацией template<> struct MakeTypelist<int, bool, NullType, NullType, ...... /* 16 NullTypes */>