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