#c #c 11 #templates #sfinae #enable-if
Вопрос:
То, что я пытаюсь сделать, — это определить функцию шаблона, которая может быть специализирована только классом, который наследует некоторые классы.
Например, у меня уже было два занятия Base1
и Base2
. Я пытаюсь определить такую функцию шаблона:
template<typename T> // if (std::is_base_of<Base1, T>::value || std::is_base_of<Base2, T>::value)
std::ostream amp; operator<<(std::ostream amp;os, const Tamp; t)
{
// os << t.member1 << t.member2...;
return os;
}
Кажется, это std::enable_if
может помочь, но я не знаю как.
Ответ №1:
C 11
template <typename T, typename = typename std::enable_if<
std::is_base_of<Base1, T>::value ||
std::is_base_of<Base2, T>::value>::type>
std::ostream amp;operator<<(std::ostream amp;os, const T amp;t) {
// os << t.member1 << t.member2...;
return os;
}
или:
template <typename T, typename std::enable_if<
std::is_base_of<Base1, T>::value ||
std::is_base_of<Base2, T>::value>::type * = nullptr>
std::ostream amp;operator<<(std::ostream amp;os, const T amp;t) {
// os << t.member1 << t.member2...;
return os;
}
Последний подход может быть полезен, когда требуется обеспечить взаимоисключающие перегрузки с ограничением SFINAE, которые отличаются только своими предикатами SFINAE. Первый подход в этом случае нежизнеспособен, поскольку две функции шаблона, отличающиеся только аргументами шаблона по умолчанию, объявляют один и тот же шаблон функции, поскольку аргументы шаблона по умолчанию не являются частью подписи шаблона функции.
C 14 (с использованием std::enable_if_t
шаблона псевдонима утилиты)
template <typename T,
typename = std::enable_if_t<std::is_base_of<Base1, T>::value ||
std::is_base_of<Base2, T>::value>>
std::ostream amp;operator<<(std::ostream amp;os, const T amp;t) {
// os << t.member1 << t.member2...;
return os;
}
C 17 (с использованием шаблонов _v
служебных переменных)
template <typename T, typename = std::enable_if_t<std::is_base_of_v<Base1, T> ||
std::is_base_of_v<Base2, T>>>
std::ostream amp;operator<<(std::ostream amp;os, const T amp;t) {
// os << t.member1 << t.member2...;
return os;
}