Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ambiguous operator overload in Clang

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?

like image 940
alecov Avatar asked Jan 12 '18 03:01

alecov


1 Answers

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.

like image 139
ecatmur Avatar answered Oct 11 '22 08:10

ecatmur