Выбор перегрузки SFINAE для оператора имеет или не имеет & lt; & lt ;?

Рассмотрим эти две функции:

template <class Type,
class = typename std::enable_if</*HAS OPERATOR <<*/>::type>
void f(std::ostream& stream, const Type& value);

template <class Type,
class... DummyTypes,
class = typename std::enable_if<sizeof...(DummyTypes) == 0>::type>
void f(std::ostream& stream, const Type& value, DummyTypes...);

Поскольку невариатическая перегрузка имеет приоритет над вариадической, я хочу проверить, имеет ли тип operator<< с std::ostream с помощью std::enable_if в первой версии.

Так что я должен написать вместо /*HAS OPERATOR <<*/ ?

0

Решение

Следующее должно работать

template <class Type,
class = decltype(std::declval<std::ostream&>() << std::declval<Type>())>
void f(std::ostream& stream, const Type& value)
{
stream << value;
}

(обратите внимание, вам не нужно использовать std::enable_if в этом случае)

6

Другие решения

Используя конечный тип возврата (1), вы можете иметь предвкушение понятий:

template <typename Type>
auto f(std::ostream& out, Type const& t) -> decltype(out << t, void()) {
// ...
}

Из-за SFINAE эту перегрузку можно выбрать, только если тип out << t может быть решена, и это означает, что перегрузка << существует, который принимает оба параметра.

Единственный недостаток в том, что это не работает, если вам нужно противоположность, это включает функцию, если эта перегрузка не существует. В этом случае enable_if стратегия (и симметричная disable_if) надо, насколько я знаю.

(1) спасибо Simple за помощь в синтаксисе

6

Проще всего проверить, когда у вас есть аргументы, то есть я бы предпочел использовать что-то вроде этого:

template <typename Type>
auto f(std::ostream& out, Type const& value)
-> typename std::enable_if<sizeof(out << value) != 0>::type {
...
}

Подобный эффект можно получить, используя std::declval() но я не уверен в создании ссылок.

2
По вопросам рекламы [email protected]