C++20(三路比较运算符)

目录

[一 三路比较运算符](#一 三路比较运算符)

[二 类重载运算符](#二 类重载运算符)

[三 比较类别](#三 比较类别)


一 三路比较运算符

在 C++ 20 之前要求自定义类型支持比较,就要重载 operator < > == != >= <= 这些比较符,而 C++ 20 提供了 <=> 三路比较运算符,又称 宇宙飞船运算符,他同时兼具了上述的所有比较符的逻辑,统一了接口,不必写冗余的代码。

示例:

cpp 复制代码
auto 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 接收这里后面讲。

二 类重载运算符

类重载三路比较运算符,语法:

cpp 复制代码
class Point
{ ... };

auto operator<=>(const Point& rhs)const
{
    ....
}

强制生成生成默认的 <=> :

cpp 复制代码
auto 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 表示。

cpp 复制代码
using _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 里,当进行 < > != >= <= 会转换成:

cpp 复制代码
void _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 ,否则调用只有声明没有定义的函数。

当然除了上述的常规的运算符比较,也可以写成:

cpp 复制代码
std::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 对象。

相关推荐
啟明起鸣8 天前
【C++20新特性】概念约束特性与 “模板线程池”,概念约束是为了 “把握未知对象”
开发语言·c++·c++20·模板线程池
linweidong9 天前
虎牙C++面试题及参考答案(上)
stl·vector·线程·内存管理·c++20·c++面试·c++调用
吐泡泡_10 天前
C++20(概念和约束)
c++20
訫悦13 天前
体验在Qt中简单使用C++20的协程
qt·c++20·协程
fpcc17 天前
C++20中的预处理器宏——__VA_OPT__
c++20
Codeking__20 天前
C++20的consteval和constinit(接C++11的constexpr)
算法·c++20
六bring个六22 天前
C++20协程
c++20·协程
C++实习生22 天前
Visual C++ 2005 Express 中文版
express·c++20
Ethan Wilson24 天前
VS2019 C++20 模块相关 C1001: 内部编译器错误
开发语言·c++·c++20