Consider the following:
template<typename T>
struct C {};
template<typename T, typename U>
void operator +(C<T>&, U);
struct D: C<D> {};
struct E {};
template<typename T>
void operator +(C<T>&, E);
void F() { D d; E e; d + e; }
This code compiles fine on both GCC-7 and Clang-5. The selected overload for operator +
is that of struct E
.
Now, if the following change takes place:
/* Put `operator +` inside the class. */
template<typename T>
struct C {
template<typename U>
void operator +(U);
};
that is, if operator +
is defined inside the class template, instead of outside, then Clang yields ambiguity between both operator +
s present in the code. GCC still compiles fine.
Why does this happen? Is this a bug in either GCC or Clang?
This is a bug in gcc; specifically, https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53499 .
The problem is that gcc is regarding the implicit object parameter of a class template member function as having a dependent type; that is, during function template partial ordering gcc transforms
C<D>::template<class U> void operator+(U); // #1
into
template<class T, class U> void operator+(C<T>&, U); // #1a (gcc, wrong)
when it should be transformed into
template<class U> void operator+(C<D>&, U); // #1b (clang, correct)
We can see that when compared to your
template<class T> void operator+(C<T>&, E); // #2
#2
is better than the erroneous #1a
, but is ambiguous with #1b
.
Observe that gcc incorrectly accepts even when C<D>
is not a template at all - i.e., when C<D>
is a class template full specialization:
template<class> struct C;
struct D;
template<> struct C<D> {
// ...
This is covered by [temp.func.order]/3, with clarification in the example. Note that again, gcc miscompiles that example, incorrectly rejecting it but for the same reason.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With