#include <iostream>
template<typename T>
struct A{};
struct Y{
template<typename T>
bool operator==(A<T>){
std::cout<<"#1\n";
return true;
}
};
template<typename T>
bool operator==(T,Y){
std::cout<<"#2\n";
return true;
}
int main(){
A<int> a;
Y y;
a==y;
}
For the above snippet, GCC prints #2 while Clang prints #1. The result is here. I think Clang is right, since #2 is a non-rewritten non-member candidate for the expression a==y. Instead, the synthesized candidate for #1 is also a viable function. That is, the overload set would consist of two candidates, which look like:
#1'
bool operator==(A<int>,Y); [with T = int] // synthesized candidate for #1
#2'
bool operator==(A<int>,Y);[with T = A<int>]
According to temp.func.order#3
If exactly one of the function templates was considered by overload resolution via a rewritten candidate ([over.match.oper]) with a reversed order of parameters, then the order of the function parameters in its transformed template is reversed.
The P/A pairs are the following:
transformed type for #1: (A<uniqueT1>, Y) as A
original type for #2: (T, Y) as P
transformed type for #2: (UniqueT2, Y) as A
original type for #1: (Y, A<UniqueT1>) as P
For the above candidates, the template function's partial ordering is sufficient to determine which is the best viable. which is bullet over.match.best#2.5
for some argument j, ICSj(F1) is a better conversion sequence than ICSj(F2), or, if not that,
2.5 F1 and F2 are function template specializations, and the function template for F1 is more specialized than the template for F2 according to the partial ordering rules described in [temp.func.order], or, if not that,
[2.6 - 2.7]
2.8 F2 is a rewritten candidate ([over.match.oper]) and F1 is not
That means that it's not necessary to step into bullet 2.8. According to the above P/A pairs, #1 is at least as specialized as #2 but #2 is not at least as specialized as #1; Hence, #1' is the best viable candidate in partial ordering. So, Clang should be correct here.
However, consider the following variant snippet
#include <iostream>
template<class T>
struct A{};
class Y{};
template<class T>
bool operator==(Y,A<T>){
std::cout<<"#1\n";
return true;
}
template<class T>
bool operator ==(T,Y){
std::cout<<"#2\n";
return true;
}
int main(){
A<int> a;
Y y{};
a == y;
}
At this time, Both Clang and GCC agree that #2 is the best viable candidate. The result is here. However, it appears to me that this example is similar to the first. Merely, it changes the member candidate to be a non-member candidate. Again, the overload set would consist of two candidates, which look like:
#1''
bool operator==(A<int>,Y); [with T = int] // synthesized candidate for #1
#2''
bool operator==(A<int>,Y); [with T = A<int>]
In this example, partial ordering is also sufficient to determine which candidate is the best. Hence, #1'' still should be the best. Why do Clang and GCC both think #2 is the best in this example?