Consider the following useless code:
struct S{
constexpr operator int() const { return 0; }
constexpr auto operator<=>(S) const { return *this; }
};
static_assert(S{} <= S{});
Clang and MSVC accept this code but GCC rejects it with an error message:
error: no match for 'operator<=' (operand types are 'S' and 'int')
Which compiler is right? How operator<=
is synthesized from operator<=>
?
From [over.match.oper] (3.4.1 and 8):
For the relational ([expr.rel]) operators, the rewritten candidates include all non-rewritten candidates for the expression x <=> y.
and
If a rewritten
operator<=>
candidate is selected by overload resolution for anoperator @
,x @ y
is interpreted as [...](x <=> y) @ 0
[...], using the selected rewrittenoperator<=>
candidate. Rewritten candidates for theoperator @
are not considered in the context of the resulting expression.
So for the expression S{} <= S{}
the selected operator will be S::operator<=>(S) const
and the expression will be rewritten as (S{} <=> S{}) <= 0
. In the rewritten expression the types of the operands are S
and int
, for which the built-in operator<=(int, int)
will be selected. So ultimately the expression (after converting S
to an int
) will result in 0 <= 0
, which is true
.
In conclusion Clang and MSVC are right in this case, and GCC seems to fail in interpreting (S{} <=> S{}) <= 0
as a call to the built-in operator (notice the error message reading operand types are 'S' and 'int'
). If you change the condition in the static_assert
to be the rewritten expression (S{} <=> S{}) <= 0
, then all three compilers accept it.
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