SFINAE выбор перегрузки для имеет или не имеет оператора <<?

0

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

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 <<*/?

Теги:
c++11
operators
sfinae
enable-if

3 ответа

6
Лучший ответ

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

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 для поддержки синтаксиса

2

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

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

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

  • 0
    sizeof(decltype(...)) не требуется, вы можете использовать sizeof(...) непосредственно для выражения.
  • 1
    Это настоящая боль, что нельзя использовать void в регулярных выражениях. decltype(out << value, void{}) будет намного проще.
Показать ещё 4 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню