三向比较运算符结果类型的重载比较运算符

Overloading comparison operators for result types of three-way comparison operators

在 C++20 中,我们得到了一个新的三向比较 operator <=> ,通常是 returns std::strong_orderingstd::partial_ordering 类型。而如果 class Aoperator <=>,那么它的对象 a1 < a2 的比较被解释为 (a1 <=> a2) < 0.

但是用户可以重载比较运算符,第一个参数为 std::strong_ordering 类型,第二个参数接受 0 字面量吗?例如:

#include <compare>
#include <iostream>

struct A { 
    std::strong_ordering operator <=>(const A &) const = default; 
};

void operator < (std::strong_ordering, std::nullptr_t) {
    std::cout << "overloaded< ";
}

int main() { 
    A{} < A{}; // #1
    (A{} <=> A{}) < 0; //#2
}

这里 GCC 和 Clang 都调用重载 operator <,即使没有任何关于标准库中存在另一个运算符的警告。可以吗?演示:https://gcc.godbolt.org/z/zEEP45Ezj

MSVC 的行为更有趣。在 #1 中它打印出一个奇怪的错误:

error C2088: '<': illegal for struct

在 #2 中:

error C2593: 'operator <' is ambiguous
<source>(8): note: could be 'void operator <(std::strong_ordering,std::nullptr_t)'
C:/data/msvc/14.30.30423-Pre/include\compare(189): note: or       'bool std::operator <(const std::strong_ordering,std::_Literal_zero) noexcept' [found using argument-dependent lookup]
<source>(14): note: while trying to match the argument list '(std::strong_ordering, int)'

就我个人而言,我更喜欢这种行为,但这里正确的行为是什么?

标准没有说明 unspecified 类型 strong_ordering 的比较,除了它接受文字 0 完全正确(使用其他任何东西都是未定义的)。

特别是,它没有指定将文字 0 转换为参数类型所涉及的隐式转换序列的种类。如果实现使用 class 类型作为参数,那么您将获得一个用户定义的转换序列,该序列会丢失到您的 operator<0nullptr_t 的标准转换;如果它也使用 nullptr_t ,那么它就不明确了;如果它使用 int,那么你的重载就会丢失。

只是...不要这样做。