https://gcc.gnu.org/bugzilla/show_bug.cgi?id=104425

            Bug ID: 104425
           Summary: SFINAE hard error on failed resolution of << for
                    defined class in namespace
           Product: gcc
           Version: 11.2.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: saalvage at gmail dot com
  Target Milestone: ---

namespace A { class foo {}; }
namespace B { class bar {}; }

A::foo& operator<<(A::foo& f, const B::bar&) { return f; }

namespace C {
    template <typename T>
    T val();

    class asd {};
    A::foo& operator<<(A::foo& f, const asd& in) { return f; }

    template <typename T, typename = void>
    struct has_insertion_operator {
        static constexpr bool value = false;
    };

    template <typename T>
    struct has_insertion_operator<T, decltype(val<A::foo&>() << val<T>(),
void())> {
        static constexpr bool value = true;
    };
}

int main() { C::has_insertion_operator<B::bar>::value; }

Produces:
<source>: In instantiation of 'struct C::has_insertion_operator<B::bar>':
<source>:24:47:   required from here
<source>:19:62: error: no match for 'operator<<' (operand types are 'A::foo'
and 'B::bar')
   19 |     struct has_insertion_operator<T, decltype(val<A::foo&>() <<
val<T>(), void())> {
      |                                              
~~~~~~~~~~~~~~~^~~~~~~~~~~
<source>:11:13: note: candidate: 'A::foo& C::operator<<(A::foo&, const
C::asd&)'
   11 |     A::foo& operator<<(A::foo& f, const asd& in) { return f; }
      |             ^~~~~~~~
<source>:11:46: note:   no known conversion for argument 2 from 'B::bar' to
'const C::asd&'
   11 |     A::foo& operator<<(A::foo& f, const asd& in) { return f; }
      |                                   ~~~~~~~~~~~^~
<source>:19:62: error: no match for 'operator<<' (operand types are 'A::foo'
and 'B::bar')
   19 |     struct has_insertion_operator<T, decltype(val<A::foo&>() <<
val<T>(), void())> {
      |                                              
~~~~~~~~~~~~~~~^~~~~~~~~~~
<source>:11:13: note: candidate: 'A::foo& C::operator<<(A::foo&, const
C::asd&)'
   11 |     A::foo& operator<<(A::foo& f, const asd& in) { return f; }
      |             ^~~~~~~~
<source>:11:46: note:   no known conversion for argument 2 from 'B::bar' to
'const C::asd&'
   11 |     A::foo& operator<<(A::foo& f, const asd& in) { return f; }
      |                                   ~~~~~~~~~~~^~
<source>:19:62: error: no match for 'operator<<' (operand types are 'A::foo'
and 'B::bar')
   19 |     struct has_insertion_operator<T, decltype(val<A::foo&>() <<
val<T>(), void())> {
      |                                              
~~~~~~~~~~~~~~~^~~~~~~~~~~
<source>:11:13: note: candidate: 'A::foo& C::operator<<(A::foo&, const
C::asd&)'
   11 |     A::foo& operator<<(A::foo& f, const asd& in) { return f; }
      |             ^~~~~~~~
<source>:11:46: note:   no known conversion for argument 2 from 'B::bar' to
'const C::asd&'
   11 |     A::foo& operator<<(A::foo& f, const asd& in) { return f; }
      |                                   ~~~~~~~~~~~^~
<source>:20: confused by earlier errors, bailing out

Notably, the same candidate appears to be reinspected thrice?

Bizzarely enough, both of the following fix the issue:
- Calling operator<< explicitely
- Only declaring, not defining B::bar

Reply via email to