Как определить функцию шаблона с помощью std::enable_if

#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;
}