It appears that the latest Visual Studio compiler can generate operator <=>(...) = default
with only 3 standard return types: std::strong_ordering
, std::weak_ordering
, std::partial_ordering
. But is it consistent with the standard?
The most reduced (however purely theoretical) example #1 is as follows:
struct A {
void operator<=>(const A &) const = default;
};
As far as I can see, the only requirement to be satisfied here for a class without subobjects is validity of static_cast<void>(std::strong_ordering::equal)
, see class.spaceship#3. And indeed both GCC and Clang accept this program, while MSVC complains (demo #1):
error C7634: 'void': is not a valid comparison type; consider using 'std::strong_ordering' instead
A longer and more practical example #2:
#include <compare>
struct A {
int a;
constexpr bool operator==(const A & r) const { return a == r.a; }
constexpr int operator<=>(const A & r) const { return a - r.a; }
};
static_assert(A{1} < A{2});
static_assert(A{3} >= A{2});
struct S : std::strong_ordering {
constexpr S(std::strong_ordering b) : std::strong_ordering(b) {}
constexpr S(int b) : std::strong_ordering(b <=> 0) {}
};
struct B : A {
int b;
S operator<=>(const B &) const = default;
};
static_assert(B{{1},2} < B{{2},1});
static_assert(B{{1},1} <= B{{1},1});
static_assert(B{{3},2} > B{{2},3});
static_assert(B{{2},2} == B{{2},2});
which has custom return type S
for spaceship operator able to be constructed from the result of subobject’s comparison operator. This program is again accepted by GCC and Clang, but MSVC first complains and then crashes (demo #2):
<source>(19): error C2280: 'S B::operator <=>(const B &) const': attempting to reference a deleted function
<source>(16): note: see declaration of 'B::operator <=>'
INTERNAL COMPILER ERROR in 'Z:compilersmsvc14.40.33807-14.40.33811.0binHostx64x64cl.exe'
Are both program examples above well formed and Visual Studio’s errors are incorrect?