首页 > 编程语言 >C++20 新特性: 三向比较运算符

C++20 新特性: 三向比较运算符

时间:2024-06-09 13:29:22浏览次数:12  
标签:std 20 三向 运算符 ordering 重载 比较

目录标题


C++20 引入了一种新的比较运算符,称为“三向比较运算符”或“太空船运算符”,其符号为 <=>。这个运算符提供了一种简化方式来同时比较两个值的相等性、小于和大于状态。这一特性主要旨在简化代码并改善性能,通过一次操作就能得到完整的比较结果。

功能和用法

三向比较运算符返回一个名为 std::strong_orderingstd::weak_orderingstd::partial_ordering 的特殊类型,这些类型都是从 std::compare_three_way 派生的。它们可以表达小于、等于、大于三种状态:

  • std::strong_ordering::less:表示左侧值小于右侧值。
  • std::strong_ordering::equal:表示两个值相等。
  • std::strong_ordering::greater:表示左侧值大于右侧值。

示例代码

考虑以下结构体 Point,使用三向比较运算符来比较两个点:

#include <compare>
#include <iostream>
struct Point {
    int x, y;

    auto operator<=>(const Point& other) const = default;  // 使用默认生成的比较
};

int main() {
    Point p1{1, 2};
    Point p2{1, 3};

    auto result = p1 <=> p2;

    if (result == std::strong_ordering::less) {
        std::cout << "p1 is less than p2";
    } else if (result == std::strong_ordering::equal) {
        std::cout << "p1 is equal to p2";
    } else if (result == std::strong_ordering::greater) {
        std::cout << "p1 is greater than p2";
    }
}

以上代码中,Point 结构体包含两个成员变量:xy,都是整数类型。结构体重载了三向比较运算符 <=>,使用默认方式生成,这意味着比较会按成员顺序进行:首先比较 x,如果 x 相等,则比较 y

这里的三向比较运算符 <=> 返回一个 std::strong_ordering 类型的结果,表示两个对象的相对大小关系。

  • p1 初始化为 {1, 2}(即 x=1, y=2)。
  • p2 初始化为 {1, 3}(即 x=1, y=3)。

当使用 p1 <=> p2 进行比较时,首先比较它们的 x 值。由于 p1.xp2.x 都是 1,所以相等,比较进入下一步,比较 y 值。此时,p1.y 是 2,而 p2.y 是 3,所以 p1 小于 p2,因此 result 的值为 std::strong_ordering::less

在我们的 main 函数中,根据 result 的值,输出相应的信息。因此,最终输出将是 “p1 is less than p2”,表示点 p1 在按 x 后 y 的顺序比较时小于点 p2


当然,三向比较运算符 <=> 在 C++20 中也可以用于运算符重载。这使得开发者能够为自定义类型定义一种自然的比较逻辑,通过一次比较即可判断出小于、等于或大于的关系。这种能力特别适用于那些需要经常进行排序或比较的数据结构。

如何重载三向比较运算符

当你重载 <=> 运算符时,你可以选择返回 std::strong_orderingstd::weak_orderingstd::partial_ordering,这取决于你的类型是否总是可以完全排序。

  • std::strong_ordering:适用于那些总是可以完全比较的类型。
  • std::weak_ordering:适用于比较可能因等价元素的不同而不完全的类型。
  • std::partial_ordering:适用于可能不具有全序性的类型(如浮点数)。

示例:重载三向比较运算符

这里有一个简单的示例,展示如何为一个包含整数成员的类重载 <=> 运算符:

#include <iostream>
#include <compare>

class Widget {
public:
    int value;
    int priority;

    Widget(int v, int p) : value(v), priority(p) {}

    // 自定义三向比较运算符的逻辑
    auto operator<=>(const Widget& other) const {
        if (auto p = priority <=> other.priority; p != 0) {
            return p; // 如果优先级不同,根据优先级比较结果返回
        }
        return value <=> other.value; // 如果优先级相同,根据值比较结果返回
    }
};

int main() {
    Widget w1(10, 2), w2(20, 1);

    auto result = w1 <=> w2;
    if (result < 0) {
        std::cout << "w1 is less important or has a lower value than w2";
    } else if (result == 0) {
        std::cout << "w1 is equal to w2";
    } else if (result > 0) {
        std::cout << "w1 is more important or has a higher value than w2";
    }
}

在这个示例中,我们使用 <=> 来定义 Widget 类的比较逻辑。此逻辑首先比较对象的 priority 成员。当使用 <=> 运算符比较两个 int 类型的 priority 成员时,结果的类型被自动推导为 std::strong_ordering,因为整型比较总是提供一个全序比较结果。

如果 priority 的比较结果不为零(即它们不相等),则直接返回该结果,表示一个对象比另一个对象“更大”或“更小”。

只有当两个对象的 priority 相等时,我们才会继续比较 value 成员。此处同样使用 <=> 运算符比较 int 类型的 value,结果也自动推导为 std::strong_ordering。我们不需要为每一种比较类型定义重载版本的比较运算符。只需要定义一个 <=> 运算符,并根据我们成员变量的类型和比较逻辑选择合适的返回类型。例如,如果类包含浮点数,auto会选择返回 std::partial_ordering

这种方式确保了比较操作符的返回类型一致性,并且符合我们特定的业务逻辑,即在 priority 相同的情况下,通过 value 的大小进一步区分对象的排序。

整体上,这种比较方法使得 Widget 类的实例比较操作不仅简洁高效,还能确保对象间的比较遵循我们设定的“优先级首先,然后是值”的逻辑,从而满足特定的业务需求,如视优先级较高的对象为“更重要”或“更优先”。

注意事项

  1. 隐式重载 == 运算符:在 C++20 中,如果你为类重载了 <=> 运算符,并且类中所有参与比较的成员也重载了 == 运算符,那么 == 运算符将被隐式地重载。如果需要不同的比较逻辑,应显式重载 == 运算符。
  2. 支持全序关系:使用 <=> 运算符时,确保参与比较的数据类型支持全序关系。对于可能不具有全序特性的类型(如浮点数),应使用 std::partial_ordering
  3. 复杂类成员的手动实现:对于包含复杂成员变量的类,可能需要手动实现 <=> 运算符来确保正确的行为,尤其是在类的成员变量比较复杂或者不直接支持 <=> 运算符时。

这些注意事项强调了在实现和使用三向比较运算符时需要考虑的关键点,确保类型比较操作符的正确使用和实现。

结语

在我们的编程学习之旅中,理解是我们迈向更高层次的重要一步。然而,掌握新技能、新理念,始终需要时间和坚持。从心理学的角度看,学习往往伴随着不断的试错和调整,这就像是我们的大脑在逐渐优化其解决问题的“算法”。

这就是为什么当我们遇到错误,我们应该将其视为学习和进步的机会,而不仅仅是困扰。通过理解和解决这些问题,我们不仅可以修复当前的代码,更可以提升我们的编程能力,防止在未来的项目中犯相同的错误。

我鼓励大家积极参与进来,不断提升自己的编程技术。无论你是初学者还是有经验的开发者,我希望我的博客能对你的学习之路有所帮助。如果你觉得这篇文章有用,不妨点击收藏,或者留下你的评论分享你的见解和经验,也欢迎你对我博客的内容提出建议和问题。每一次的点赞、评论、分享和关注都是对我的最大支持,也是对我持续分享和创作的动力。


阅读我的CSDN主页,解锁更多精彩内容:泡沫的CSDN主页
在这里插入图片描述

标签:std,20,三向,运算符,ordering,重载,比较
From: https://blog.csdn.net/qq_21438461/article/details/139560630

相关文章

  • 2024-6-9 石群电路-27
    2024-6-9,星期日,12:49,天气:晴,心情:晴。Hello,大家,我回来啦,昨天断更了一天,是为什么捏,是因为,我通过毕业答辩啦!!!!!!果然,虽然是小小硕士,但是听到那句,“经答辩委员会决议,xx同学通过毕业论文答辩,建议授予工学硕士学位”,也是很爽的,至于博士大佬听到这句话什么感想,小子就先不想啦,哈哈哈哈哈,加油......
  • SuntoryProgrammingContest2024(AtCoder Beginner Contest 357)
    A-SanitizeHands题意:给定一个序列和m,问m按顺序减去这个序列,m>=0情况下最多能减多少个数思路:前缀和+prev(upper_bound())总结:disinfectan(消毒ji),disinfect(消毒,杀毒),aliens(外星人),voidsolve(){ intn,m; cin>>n>>m; vector<int>a(n); for(inti=......
  • CSP历年复赛题-P3957 [NOIP2017 普及组] 跳房子
    原题链接:https://www.luogu.com.cn/problem/P3957题意解读:有n个格子,每个格子有不同的距离和分数,从起点,每次可跳距离为d,用g金币后可跳距离范围可以变成max(d-g,1)~d+g,求最小的g,使得可跳跃得分不少于k。解题思路:1、单调性分析:如果g越大,可跳跃的范围就越大,理论上能得的分数越......
  • 最新区块链论文速读--CCF A会议 CCS 2023 共25篇 附pdf下载(3/4)
    Conference:ACMConferenceonComputerandCommunicationsSecurity(CCS)CCFlevel:CCFACategories:networkandinformationsecurityYear:2023Num:25第1~7篇区块链文章请点击此处查看第8~13篇区块链文章请点击此处查看14Title: FuzzontheBeach:FuzzingSo......
  • P4568 [JLOI2011] 飞行路线
    题目P4568[JLOI2011]飞行路线要求找到在最多可以免费乘坐k条航线的情况下,从城市s到城市t的最少花费。这是一个典型的分层图问题。分层图的建模1.建立层次将原图分成k+1层,表示在0到k次免费乘坐的情况下的状态。第i层表示已经使用了i次免费乘坐机会的状态。2.建立节点和边......
  • 2024050801-重学 Java 设计模式《实战策略模式》
    重学Java设计模式:实战策略模式「模拟多种营销类型优惠券,折扣金额计算策略场景」一、前言文无第一,武无第二不同方向但同样努力的人,都有自身的价值和亮点,也都是可以互相学习的。不要太过于用自己手里的矛去攻击别人的盾......
  • 【题解】[CSP-J 2019] 公交换乘
    题目描述题目大意给出\(n\)次出行记录(地铁或公交车),有以下优惠方案:搭乘一次地铁后可以获得一张有效期为45分钟的优惠票,可以免费搭乘一次票价不超过该地铁票价的公交车。优惠票可以累计存储优先使用过期时间早的优惠票。思路枚举每一次出行:如果是地铁。累加花费,并记......
  • 【资源分享】MATLAB 2024a免费下载安装
    :::block-1“时问桫椤”是一个致力于为本科生到研究生教育阶段提供帮助的不太正式的公众号。我们旨在在大家感到困惑、痛苦或面临困难时伸出援手。通过总结广大研究生的经验,帮助大家尽早适应研究生生活,尽快了解科研的本质。祝一切顺利!——时问桫椤:::获取方法“时问桫......
  • 打卡信奥刷题(67)用Scratch图形化工具信奥P1125 [NOIP2008 提高组] 笨小猴,写了一个好用
    [NOIP2008提高组]笨小猴题目描述笨小猴的词汇量很小,所以每次做英语选择题的时候都很头疼。但是他找到了一种方法,经试验证明,用这种方法去选择选项的时候选对的几率非常大!这种方法的具体描述如下:假设maxn......
  • Python 运算符重载
    在Python中,运算符重载是一种允许你定义或修改内置运算符(例如+,-,*,/等)在自定义类中的行为的技术。通过重载运算符,你可以使这些运算符对自定义对象执行特定的操作。运算符重载是通过在类中定义特殊方法(也称为魔法方法)来实现的,这些方法通常以双下划线开头和结尾。以下是一些常......