I am just researching a three-way comparison operator <=>
. I see that it returns std::strong_ordering
. However, I fail to understand how the compiler is restricting only 0
in comparison operators (so<0
, but not so<1
)
#include<compare>
int main()
{
std::strong_ordering so = 55 <=> 10;
so < 0; // Fine
so < 1; // Fails
}
Similarly, so>20
won't work either. Following also won't work:
constexpr int Zero = 0;
so == Zero; // Error
so == 0; // Fine
EDIT - Interesting observation (on MSVC compiler). Following is valid:
so < nullptr
Using anything but a literal 0
to compare against std::strong_ordering
is explicit undefined behavior, see [cmp.categories.pre]/3 of the C++20 draft.
It is up to the compiler/standard library how or whether this is enforced/diagnosed.
One way of achieving a diagnostic for the UB without any compiler magic is to use std::nullptr_t
as argument to the overloaded comparison operator of std::strong_ordering
(which has unspecified type according to the standard). Any integral zero literal can be implicitly converted to std::nullptr_t
, but literals with other values or constant expressions that are not literals, cannot. See [conv.ptr]/1.
This is also mentioned in a draft note as possibility.
Libc++ seems to instead use a member pointer to some hidden class, see here.
Libstdc++ seems to do something similar, using a hidden class type that needs to be constructed from a pointer to itself, see here.
However neither of these implementations diagnose all arguments that result in UB according to the standard. In particular all of them also accept nullptr
as argument without diagnostic: https://godbolt.org/z/esnvqR
I suppose full diagnosis of all the cases would require some compiler magic.