Edit: The original version of this answer said that GCC was correct. I now believe that Clang is correct according to the wording of the standard, but I can see how GCC's interpretation could also be correct.
Let's look at your first example, where the two declarations are:
template<typename T, typename U>
void operator +(C<T>&, U);
void operator +(C<T>&, E);
Both are viable, but it is obvious that the second template is more specialized than the first. So GCC and Clang both resolve the call to the second template. But let's walk through [temp.func.order] to see why, in the wording of the standard, the second template is more specialized.
The partial ordering rules tell us to replace each type template parameter with a unique synthesized type and then perform deduction against the other template. Under this scheme, the first overload type becomes
and deduction against the second template fails since the latter only accepts
E. The second overload type becomes
and deduction against the first template succeeds (with
E). Since the deduction succeeded in only one direction, the template that accepted the other's transformed type (the first one) is considered less specialized, and thus, the second overload is chosen as the more specialized one.
When the second overload is moved into class
C, both overloads are still found and the overload resolution process should apply in exactly the same way. First, the argument list is constructed for both overloads, and since the first overload is a non-static class member, an implied object parameter is inserted. According to [over.match.funcs], the type of that implied object parameter should be "lvalue reference to
C<T>" since the function does not have a ref-qualifier. So the two argument lists are both
(C<D>&, E). Since this fails to effect a choice between the two overloads, the partial ordering test kicks in again.
The partial ordering test, described in [temp.func.order], also inserts an implied object parameter:
If only one of the function templates
M is a non-static member of
M is considered to have a new first parameter inserted in its function parameter list. Given cv
as the cv-qualifiers of
M (if any), the new parameter is of type “rvalue reference to cv
A” if the optional
&& or if
M has no ref-qualifier and the first parameter of the other template has rvalue
reference type. Otherwise, the new parameter is of type “lvalue reference to cv
A”. [ Note: This allows a
non-static member to be ordered with respect to a non-member function and for the results to be equivalent
to the ordering of two equivalent non-members. — end note ]
This is the step where, presumably, GCC and Clang take different interpretations of the standard.
My take: The member
operator+ has already been found in the class
C<D>. The template parameter
T for the class
C is not being deduced; it is known because the name lookup process entered the concrete base class
D. The actual
operator+ that is submitted to partial ordering therefore does not have a free
T parameter; it is not
void operator+(C<T>&, U), but rather,
void operator+(C<D>&, U).
Thus, for the member overload, the transformed function type should not be
void(C<X1>&, X2), but rather
void(C<D>&, X2). For the non-member overload, the transformed function type is still
void(C<X3>&, E) as before. But now we see that
void(C<D>&, X2) is not a match for the non-member template
void(C<T>&, E) nor is
void(C<X3>&, E) a match for the member template
void(C<D>&, U). So partial ordering fails, and overload resolution returns an ambiguous result.
GCC's decision to continue to select the non-member overload makes sense if you assume that it is constructing the transformed function type for the member lexically, making it still
void(C<X1>&, X2), while Clang substitutes
D into the template, leaving only
U as a free parameter, before beginning the partial ordering test.