三向比较运算符结果类型的重载比较运算符
Overloading comparison operators for result types of three-way comparison operators
在 C++20 中,我们得到了一个新的三向比较 operator <=>
,通常是 returns std::strong_ordering
或 std::partial_ordering
类型。而如果 class A
有 operator <=>
,那么它的对象 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<
从 0
到 nullptr_t
的标准转换;如果它也使用 nullptr_t
,那么它就不明确了;如果它使用 int
,那么你的重载就会丢失。
只是...不要这样做。
在 C++20 中,我们得到了一个新的三向比较 operator <=>
,通常是 returns std::strong_ordering
或 std::partial_ordering
类型。而如果 class A
有 operator <=>
,那么它的对象 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<
从 0
到 nullptr_t
的标准转换;如果它也使用 nullptr_t
,那么它就不明确了;如果它使用 int
,那么你的重载就会丢失。
只是...不要这样做。