Не считается ли доступ к несуществующему члену "ошибкой" в отношении SFINAE? - PullRequest
0 голосов
/ 05 февраля 2019

Я реализовал перегрузку для симпатичных пар печати:

template<typename P>
ostream &operator<<(ostream &os, const P &p) {
  using std::operator<<;
  os << '(' << p.first << ", " << p.second << ')';
  return os;
}

Однако в его присутствии компилятору трудно определить, следует ли ему применять стандартную перегрузку или ту, которую я определил выше, дажев случаях, когда выбор должен быть очевидным:

int main() {
  cout << "SFINAE sure is hard to grasp!\n";
}

error: use of overloaded operator '<<' is
      ambiguous (with operand types 'std::ostream' (aka 'basic_ostream<char>') and
      'const char [30]')

Я не совсем понимаю, в чем проблема.Массив char, который я пытаюсь распечатать, явно не содержит first или second членов, поэтому создание его с моей перегрузкой может привести к ошибке.

Если SFINAE не попытается выполнить подстановку, найдитевыходит, что члену не хватает, и откажитесь от результата?Если нет, то почему?

Ответы [ 2 ]

0 голосов
/ 05 февраля 2019

SFINAE работает при разрешении перегрузки:

Это правило применяется при разрешении перегрузки шаблонов функций: при неудачной замене явно заданного или выведенного типа для параметра шаблона специализацияотбрасывается из набора перегрузок, а не вызывает ошибку компиляции.

Это означает, что только подпись шаблонов функций вступит в силу для SFINAE, реализация не будет проверена.

Вы можете изменить перегрузку на

template <typename T, typename = void>
struct pairable : std::false_type {};

// check whether type T has first and second members
template <typename T>
struct pairable<T, std::void_t<decltype(std::declval<T>().first),
                               decltype(std::declval<T>().second)>>
    : std::true_type {};

// the template parameter is the part of the signature of function template
template<typename P, std::enable_if_t<pairable<P>::value>* = nullptr>
ostream &operator<<(ostream &os, const P &p) {
  using std::operator<<;
  os << '(' << p.first << ", " << p.second << ')';
  return os;
}

LIVE

0 голосов
/ 05 февраля 2019

SFINAE применяется только к сигнатуре функции: то есть к типам аргументов, типу возвращаемого значения и квалификаторам, таким как: const, не- const.Это не относится к реализациям функций.

В вашем случае сигнатура функции соответствует вызову.Следовательно, функция создается, и ожидается, что она будет скомпилирована без ошибок.

...