#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?
Short answer: You used different Clang versions in your examples, Clang 11 has a correct implementation, while Clang 10 does not.
In my answer I go into detail why Clang 11 and MSVC are right and GCC is wrong in both cases.
From [over.match.oper]#3 the candidates include four sets:
For [...] a binary operator
@
[...] four sets of candidate functions, designated member candidates, non-member candidates, built-in candidates, and rewritten candidates, are constructed as follows:
In your case the rewritten candidates are determined by [over.match.oper]#3.4.4:
For the equality operators, the rewritten candidates also include a synthesized candidate, with the order of the two parameters reversed, for each non-rewritten candidate for the expression
y == x
.
In your case for an expression x == y
the candidates of interest are:
x.operator==(y)
operator==(x, y)
y == x
, which are y.operator==(x)
and operator==(y, x)
.Let's look at your two examples and determine the best candidate.
For the expression a == y
the candidates are:
non-rewritten candidates:
#2 via operator==(a, y)
rewritten candidates:
#1 via y.operator==(a)
To determine the better candidate we need to apply [over.match.best.general]#2, the relevant rules to determine if F1
is a better match than F2
are:
(2.5)
F1
andF2
are function template specializations, and the function template forF1
is more specialized than the template forF2
according to the partial ordering rules described in [temp.func.order], or, if not that,[...]
(2.8)
F2
is a rewritten candidate ([over.match.oper]) andF1
is not
If we take #1
to be F1
and #2
to be F2
we get that #1
is a better match, since (2.5) applies and it's considered before (2.8). Clang 11+ and the latest MSVC correctly select #1
as the better candidate here (demo).
For the expression a == y
the candidates are:
non-rewritten candidates:
#2 via operator==(a, y)
rewritten candidates:
#1 via operator==(y, a)
Applying [over.match.best.general]#2 and taking #1
to be F1
and #2
to be F2
, similarly to the first example we get that #1
is a better candidate since (2.5) applies and it's considered before (2.8). Same as in the first example Clang 11+ and the latest MSVC correctly select #1
as the better candidate (demo).
Why do Clang and GCC both think #2 is the best in this example?
The don't. In your demo link you used Clang 10, while in the first example you used Clang 11. Clang 10 has the same result as GCC in both cases.
In both cases #1
is the better candidate, which Clang 11+ and the latest MSVC correctly select. GCC fails in both cases, selecting #2
. My guess would be that GCC's implementation of [over.match.best.general]#2 is incorrect in that it wrongly consideres (2.8) before (2.5) and selects the non-rewritten candidate in both cases.
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