Consider the following two overload operator<=>
for S
:
#include <compare>
struct S {};
int operator<=>(S, int) { return 0; } #1
S operator<=>(S, S) { return {}; } #2
If I compare an object S
with an int
, the #1
will generate the right operators for me, so expression like S{} <= 0
, 0 < S{}
or 0 <=> S{}
would be just fine.
But if I compare an object S
with other object S
:
S{} < S{};
Then this will be rewritten as (S{} <=> S{}) < 0
. Since (S{} <=> S{})
will return an other S
, we back to the origin problem: S
compare with a int
. At this time, we don't have operator<(S, int)
, so #1
would generate the right operator for me.
But surprisingly, none of the three compilers do this to me. GCC, Clang, and MSVC all reject S{} < S{}
with the same error message:
no match for 'operator<' (operand types are 'S' and 'int')
This makes me frustrated. Since the #1
actually exists. Why the nested generation of the operator are not occurring here? What does the standard say? Is there a static constraint violation?
Equal to ( === ) — returns true if the value on the left is equal to the value on the right, otherwise it returns false .
This is ill-formed, although admittedly the error message is quite confusing.
The rule, from [over.match.oper]/8 is (emphasis mine):
If a rewritten
operator<=>
candidate is selected by overload resolution for an operator@
,x @ y
is interpreted as0 @ (y <=> x)
if the selected candidate is a synthesized candidate with reversed order of parameters, or(x <=> y) @ 0
otherwise, using the selected rewrittenoperator<=>
candidate. Rewritten candidates for the operator@
are not considered in the context of the resulting expression.
The expression S{} < S{}
is going to resolve to the rewritten candidate (S{} <=> S{}) < 0
. The resulting expression will not consider rewritten candidates in its lookup. So when we do S{} < 0
, that is going to look for just an operator<
, and not also operator<=>
. It can't find such a thing, so the expression is ill-formed.
<source>:8:14: error: no match for 'operator<' (operand types are 'S' and 'int')
8 | auto x = S{} < S{};
| ~~~~^~~~~
In that sense, the error is literally true: there is no match for, specifically operator<
with those operands. Although it would help if the error message had quite a bit more context explaining why it's looking for that (and I submitted a request to that effect in 99629).
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