目录
[一 三路比较运算符](#一 三路比较运算符)
[二 类重载运算符](#二 类重载运算符)
[三 比较类别](#三 比较类别)
一 三路比较运算符
在 C++ 20 之前要求自定义类型支持比较,就要重载 operator < > == != >= <= 这些比较符,而 C++ 20 提供了 <=> 三路比较运算符,又称 宇宙飞船运算符,他同时兼具了上述的所有比较符的逻辑,统一了接口,不必写冗余的代码。
示例:
cppauto result = 1 <=> 2; if (result < 0) { std::cout << "<" << std::endl; } else if (result > 0) { std::cout << "<" << std::endl; } else { std::cout << "<" << std::endl; }这里拿内置类型做比较,内置类型天然的满足 <=> 进行比较,结果用 0 判断 和 返回值用 auto 接收这里后面讲。
二 类重载运算符
类重载三路比较运算符,语法:
cppclass Point { ... }; auto operator<=>(const Point& rhs)const { .... }强制生成生成默认的 <=> :
cppauto operator<=>(const Point& rhs)const = default;如果自己写了 <=> 或者强制编译器生成默认的 <=> ,该类就可以使用传统的比较方式了,但 <=> 生成默认的要求所有的成员变量都支持 <=>,并按声明顺序进行比较,既可写成类成员函数也可写成非成员函数。
三 比较类别
前面所讲的比较结果用 auto 接收和用 0 进行比较:
用 auto 接收:<=> 比较后的结果有 3 种类型,并不是返回一个 int 类型。
用 0 判断:这 3 种类型都重载了 operator < > <= >= != 运算符。
3 种比较类别:
strong_ordering:强序比较,严格的比较,如 内置类型比较,string 逐个按字符比较等。
|---------------------------------------------------------|-------------------------------------------------------------------|
| inline constexpr std::strong_ordering less [静态] | 一个有效值,表示小于(排在前面)关系 (public static 成员常量) |
| inline constexpr std::strong_ordering equivalent [静态] | 一个有效值,表示等价(既不排在前面也不排在后面)关系,与equal相同 (public static 成员常量) |
| inline constexpr std::strong_ordering equal [静态] | 一个有效值,表示等价(既不排在前面也不排在后面)关系,与equivalent相同 (public static 成员常量) |
| inline constexpr std::strong_ordering greater [静态] | 一个有效值,表示大于(排在后面)关系 (public static 成员常量 |less:小于。
equivallent == equal:严格等于。
greater:大于。
weak_ordering:弱序比较,不严格的比较,如按自己的规则进行比较,string 忽略大小写比较等。
|-------------------------------------------------------|-----------------------------------------------|
| inline constexpr std::weak_ordering less [静态] | 一个有效值,表示小于(排在前面)关系 (public static 成员常量) |
| inline constexpr std::weak_ordering equivalent [静态] | 一个表示等价的有效值(既不排在前面也不排在后面) (public static 成员常量) |
| inline constexpr std::weak_ordering greater [静态] | 一个有效值,表示大于(排在后面)关系 (public static 成员常量) |less:小于。
equivallent :等价 - 约等于。
greater:大于。
partial_ordering:相交与前 2 个,多了一个不可比较的状态。
|----------------------------------------------------------|-----------------------------------------------|
| inline constexpr std::partial_ordering less [静态] | 一个有效值,表示小于(排在前面)关系 (public static 成员常量) |
| inline constexpr std::partial_ordering equivalent [静态] | 一个表示等价的有效值(既不排在前面也不排在后面) (public static 成员常量) |
| inline constexpr std::partial_ordering greater [静态] | 一个有效值,表示大于(排在后面)关系 (public static 成员常量) |
| inline constexpr std::partial_ordering unordered [静态] | 一个表示与不可比较值之间关系的有效值 (public static 成员常量) |less:小于。
equivallent :等价 - 约等于。
greater:大于。
unordered:不可比较。
这些静态对象都在这些比较类别里面定义好了,其值在 MSVC 下是 signed char 表示。
cppusing _Compare_t = signed char; enum class _Compare_eq : _Compare_t { equal = 0, equivalent = equal }; enum class _Compare_ord : _Compare_t { less = -1, greater = 1 }; enum class _Compare_ncmp : _Compare_t { unordered = -128 };右操作数的比较结果会放到左操作数对象的 _Value 里,当进行 < > != >= <= 会转换成:
cppvoid _Literal_zero_is_expected(); struct _Literal_zero { template <class _Ty> requires is_same_v<_Ty, int> consteval _Literal_zero(_Ty _Zero) noexcept { // Can't use _STL_VERIFY because this is a core header if (_Zero != 0) { _Literal_zero_is_expected(); } } }; _NODISCARD friend constexpr bool operator<(const strong_ordering _Val, _Literal_zero) noexcept { return _Val._Value < 0; }如果没有传 int 则会被 _Literal_zero 里的 requries 约束限制,is_same_v 作为构造的参数进行限制类型必须和 int 先等,consteval 立即函数里必须等于 0 ,否则调用只有声明没有定义的函数。
当然除了上述的常规的运算符比较,也可以写成:
cppstd::strong_ordering s1 = 1 <=> 1; if (s1 == std::strong_ordering::equal) { std::cout << "==" << std::endl; } else if (s1 == std::strong_ordering::less) { std::cout << "<" << std::endl; } else { std::cout << ">" << std::endl; } _NODISCARD friend constexpr bool operator==(strong_ordering, strong_ordering) noexcept = default;这里直接让编译器强制生成并比较里面的有符号 _Value 对象。