Почему эта ошибка замещения происходит в рефлексии на основе SFINAE? - PullRequest
2 голосов
/ 20 мая 2019

Я написал код, который определяет, может ли один объект быть передан в std::ostream.Однако, хотя он работает в Clang, он не работает в GCC.После упрощения кода возникает проблема, когда два класса имеют оператор <<, определенный в разных пространствах имен. </p>

Ниже приведен (упрощенный) код (и здесь он находится на Godbolt):

#include <iostream>

namespace test_ns {
  // Define two (trivial) classes.
  class Class1 { };
  class Class2 { };

  // First class has ostream operator defined in namespace test_ns
  std::ostream & operator<<(std::ostream & out, const Class1 & v) {
    return out << "Class1 Output!";
  }
}

// Second class as ostream operator defined in global namespace.
std::ostream & operator<<(std::ostream & out, const test_ns::Class2 & v) {
  return out << "Class2 Output!";
}

namespace test_ns {
  // Simple template that always evaluates to bool (for SFINAE-based reflection)
  template <typename EVAL_TYPE> using bool_decoy = bool;

  // Two version of HasPrint that test the operator<< into ostream.
  // First version preferred if << works...
  template <typename T>
  bool HasPrint(bool_decoy<decltype( std::declval<std::ostream&>() << std::declval<T>() )>) {
    return true;
  }

  // Second version as a fallback.
  template <typename T>
  bool HasPrint(...) {
    return false;
  }

}

int main()
{
  std::cout << test_ns::HasPrint<test_ns::Class2>(true) << std::endl;
}

Вот ошибка, которую я получаю в gcc 9.1:

<source>: In instantiation of 'bool test_ns::HasPrint(test_ns::bool_decoy<decltype ((declval<std::basic_ostream<char, std::char_traits<char> >&>() << declval<T>()))>) [with T = test_ns::Class2; test_ns::bool_decoy<decltype ((declval<std::basic_ostream<char, std::char_traits<char> >&>() << declval<T>()))> = <type error>]':

<source>:40:55:   required from here

<source>:26:68: error: no match for 'operator<<' (operand types are 'std::basic_ostream<char>' and 'test_ns::Class2')

   26 |   bool HasPrint(bool_decoy<decltype( std::declval<std::ostream&>() << std::declval<T>() )>) {

      |                                      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~

(сопровождается длинным списком кандидатов)

Пока я могу (и буду)рефакторинг кода, чтобы обойти эту проблему, я не до конца понимаю, что здесь происходит не так.Я неправильно определяю операторы, или это проблема с gcc?

1 Ответ

0 голосов
/ 21 мая 2019

Простой ответ, как намекнул NathanOliver, заключается в том, что ваш operator<< в глобальном пространстве имен не найден ADL, и он не может быть найден при неквалифицированном поиске из test_ns::HasPrint, потому что test_ns::operator<<. Интересный вопрос, почему Clang все равно находит это. Я могу только предположить, что decltype как-то сбивает с толку.

...