void_t spezialization, почему первичный шаблон должен иметь default = void?

У меня есть вопрос о метафункции void_t, показанный в этом видео https://www.youtube.com/watch?v=a0FliKwcwXE и вопрос, заданный в 41:25.

Я попытаюсь показать мой вопрос с помощью этого фрагмента кода:

template<typename _Tp, typename _Up, typename = void>
class __is_assignable_helper_af2: public std::false_type
{
};


template<typename _Tp, typename _Up>
class __is_assignable_helper_af2<_Tp, _Up,
     void_t<decltype(std::declval<_Tp&>() = std::declval<_Up&>())>> 
  : public std::true_type
{
};

Почему для первого шаблона нужен тип по умолчанию void? int не работает.

Я понимаю, что обе функции будут иметь одну и ту же сигнатуру (с void), но будет использоваться более специализированная (вторая). Но почему он не работает с int? Второй с пустотой все равно будет предпочтительным, не так ли?

Не будет ли =int соответствовать SFINAE?

Спасибо!

1 ответ

void необходимо, чтобы результат этого void_t<decltype(...)> выражение будет соответствовать аргументу по умолчанию для основного шаблона.

Подумайте о случаях, когда классы назначаются и не назначаются:

Назначаются:

void_t<decltype(std::declval<_Tp&>() = std::declval<_Up&>())>
//reduces to
void_t<type given from assignment>
//reduces to
void

Не назначаются:

void_t<decltype(std::declval<_Tp&>() = std::declval<_Up&>())>
//substitution failure, remove from candidate set

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

__is_assignable_helper_af2<_Tp, _Up, void>

Мы хотим, чтобы клиентский код просто передавал два аргумента, а не явно указывал void аргумент для SFINAE, поэтому мы указываем его в аргументах по умолчанию:

template<typename _Tp, typename _Up, typename = void>
//                                   ^^^^^^^^^^^^^^^

Мы могли бы так же легко выбрать другой тип, кроме void для этого, но его использование делает очевидным, что мы не заботимся о типе, мы просто используем его для использования SFINAE. Например, мы могли бы определить int_t и имеют int в качестве аргумента по умолчанию. Пока они совпадают, мы используем частичную специализацию, когда хотим.

Другие вопросы по тегам