Роль аргументов шаблона по умолчанию в контексте частичной специализации

Мне непонятно взаимодействие аргументов шаблона по умолчанию в контексте частичной специализации для выбора наиболее подходящего шаблона. Эти вопросы связаны с кодом, размещенным в этом -data-member">ответ от max66.

Учитывая определения классов A и B:

template <int N> struct A { static const int code = N; };

struct B{};

и следующие классы шаблонов:

// primary template
template <typename, typename Enable = bool_constant<true>>
struct cond : public bool_constant<false> {};

// specialization
template <typename T>
struct cond<T, bool_constant<(0 == T::code)>> : public bool_constant<true> {};

1) cond<B>::value оценивается как false (т. е. выбирается первичный). Это ясно, так как основной шаблон дает cond<B, bool_constant<true>>, специализация терпит неудачу, следовательно, основной шаблон является единственным возможным выбором.

2) cond<A<0>>::value оценивается как true (т.е. специализация выбрана). Это ясно, так как основной шаблон дает cond<B, bool_constant<true>>, специализация также дает cond<B, bool_constant<true>>, поэтому специализация предпочтительнее, поскольку аргумент для второго параметра шаблона задан явно.

3) cond<A<1>>::value оценивается как false (т. е. выбирается первичный). Это мне непонятно. Основной шаблон дает cond<B, bool_constant<true>>, специализация дает cond<B, bool_constant<false>>. Учитывая, что аргумент для второго параметра шаблона явно указан в специализации, почему он не предпочтителен?

Я предполагаю, что поведение в (3) связано с некоторым взаимодействием между аргументом шаблона по умолчанию основного шаблона и специализацией. В этом ответе Джерри Коффин говорит что-то, что может объяснить такое поведение:

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

Кто-нибудь может уточнить это правило? Спасибо


person Fabio    schedule 01.10.2018    source источник


Ответы (1)


template <typename, typename Enable = bool_constant<true>>
struct cond : public bool_constant<false> {};

идентичен

template <typename, typename Enable = bool_constant<true>> struct cond;

template <typename, typename Enable>
struct cond : public bool_constant<false> {};

Позже может быть яснее понять результат.

Когда вы пишете cond<C>, благодаря аргументу по умолчанию, это эквивалентно cond<C, bool_constant<true>>.

Затем мы пытаемся сопоставить это с "лучшим воплощением".

У нас есть выбор между:

// primary template
template <typename, typename Enable>
struct cond : public bool_constant<false> {};

и частичная специализация, использующая SFINAE:

// specialization
template <typename T>
struct cond<T, bool_constant<(0 == T::code)>> : public bool_constant<true> {};

Если 0 == T::code сформирован неправильно, специализация отбрасывается, и жизнеспособным решением является только первичный шаблон, поэтому он используется.

В противном случае, если 0 == T::code оценивается как false, специализация не соответствует, и также используется основной шаблон.
Обратите внимание, что при использовании cond<C, bool_constant<false>> в этом случае будет использоваться специализация.

В противном случае 0 == T::code оценивается как true, и тогда и первичная, и специализация являются жизнеспособными, но специализация является более специализированной, поэтому она выбрана.

person Jarod42    schedule 01.10.2018
comment
Не могли бы вы уточнить случай, когда 0 == T::code оценивается как false? Почему не совпадает? Почему явное использование cond<C, bool_constant<false>> вместо этого будет соответствовать? - person Fabio; 01.10.2018
comment
Как я уже сказал, cond<C> равно cond<C, bool_constant<true>>, а cond<C, bool_constant<true>> не соответствует cond<T, bool_constant<false>> (T == C, но true != false). - person Jarod42; 01.10.2018
comment
Я все еще в замешательстве. Я вижу, что не совпадает. Вопрос в том, почему это должно совпадать, чтобы быть действительной специализацией? Мое понимание аргументов шаблона по умолчанию заключается в том, что если они не указаны специально, то используется значение по умолчанию. Но если какой-либо допустимый тип указан явно, будь то bool_constant<false> или void или любой другой, он должен успешно заменить значение по умолчанию и, следовательно, быть предпочтительным. Здесь мы говорим, что это произойдет только в том случае, если это соответствует умолчанию. Каково точное правило? - person Fabio; 02.10.2018
comment
Сначала мы заполняем отсутствующие аргументы по умолчанию. так что cond<C> -> cond<C, bool_constant<true>>. Для определения основного шаблона это универсальное определение, поэтому любое cond<T, U> может использовать это определение, но не обязательно более специализированное. Версия SFINAE более специализирована, поэтому после правильного формирования она имеет приоритет над основным шаблоном (если он совпадает). - person Jarod42; 02.10.2018
comment
Хорошо, последняя часть последнего предложения - это ответ, который я искал: версия SFINAE более специализирована, поэтому после правильного формирования она имеет приоритет над основным шаблоном (если он соответствует). Вы можете подчеркнуть это в своем ответе, так как это было виновником. Любую ссылку, которую я могу прочитать? - person Fabio; 02.10.2018
comment
См. раздел partial_specialization. (Особенно Частичный заказ). - person Jarod42; 02.10.2018