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
в качестве аргумента по умолчанию. Пока они совпадают, мы используем частичную специализацию, когда хотим.