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