Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How std::strong_ordering works only with zero?

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

like image 325
Ajay Avatar asked Feb 25 '20 12:02

Ajay


1 Answers

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.

like image 75
walnut Avatar answered Oct 27 '22 23:10

walnut