当前位置: 首页 > news >正文

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

概述

        在C++中,如果需要对两个自定义类的对象进行比较,我们通常要单独定义6个比较运算符:==、!=、<、<=、>、>=。这不仅繁琐,还很容易出错,特别是当比较逻辑复杂时,稍有不慎就会引发不一致的比较结果。为了解决这个问题,提供统一的比较接口,C++ 20中引入了三向比较运算符。它能够根据操作数的相对大小,返回-1、0或1,分别代表小于、等于和大于,从而简化了比较逻辑的实现。

什么是三向比较运算符

        三向比较运算符,即<=>,通常称为“太空船运算符”(Spaceship operator)。这个运算符的设计初衷是为了简化用户自定义类型的比较操作,以前需要分别重载<、>、==等多个比较运算符,而现在仅需一个运算符就能完成所有比较逻辑的定义。

        <=>运算符在内部执行两个操作数的比较,并根据它们的相对大小返回一个特殊类型。这个类型属于std::compare_three_way的结果类型分类,具体可以是以下三种。

        std::strong_ordering:表示强顺序关系,返回std::strong_ordering::less、std::strong_ordering::equal、或std::strong_ordering::greater。

        std::weak_ordering:用于可能无法区分所有不同值的情况,比如NaN在浮点数比较中的处理。

        std::partial_ordering:适用于部分可比类型,比如某些情况下可能会出现不可比较的值。

如何使用

        对于简单的自定义类型,可以直接在类中使用= default默认定义<=>运算符,可参考下面的示例代码。

#include <compare>
#include <iostream>
using namespace std;struct Fraction
{int numerator;int denominator;Fraction(int num, int denom) : numerator(num), denominator(denom) {}// 重载三向比较运算符auto operator<=>(const Fraction& other) const = default;
};int main()
{Fraction f1(1, 2);Fraction f2(2, 4);if (f1 <=> f2 == 0){cout << "f1 and f2 are equal." << endl;}else if (f1 <=> f2 < 0){cout << "f1 is less than f2." << endl;}else{cout << "f1 is greater than f2." << endl;}return 0;
}

        在上面的示例代码中,operator<=>使用= default请求编译器生成比较逻辑。编译器会自动比较Fraction实例的numerator和denominator字段,如果两者都相等,则认为两个Fraction实例相等。如果numerator不等,则根据numerator的比较结果决定。如果numerator相同但denominator不等,则根据denominator的比较结果决定。

        有时候,默认生成的比较逻辑并不合适,就比如上面的例子。对于复杂的比较逻辑,可以手动实现<=>运算符,然后根据具体情况返回相应的比较结果。

        在下面的示例代码中,我们定义了一个Person结构体,并为它提供了三向比较运算符的重载函数。这个函数首先比较两个Person对象的年龄,如果年龄不同,则直接返回年龄的比较结果。如果年龄相同,则比较姓名。通过这种方式,我们可以很容易地实现自定义类型的比较功能,并且只需要一个比较函数就可以满足各种比较需求。

#include <compare>
#include <iostream>
#include <string>
using namespace std;struct Person
{std::string name;int age;auto operator<=>(const Person& other) const{// 先按年龄比较if (age != other.age){return age <=> other.age;}// 年龄相同则按姓名比较return name <=> other.name;}
};int main()
{Person p1{ "Mike", 18 };Person p2{ "Jack", 20 };std::cout << std::boolalpha;std::cout << (p1 < p2) << endl;std::cout << (p1 > p2) << endl;// 使用三向比较运算符的返回值  auto result = p1 <=> p2;if (result < 0){std::cout << "p1 is less than p2" << endl;}else if (result == 0){std::cout << "p1 is equal to p2" << endl;}else{std::cout << "p1 is greater than p2" << endl;}return 0;
}

总结

        三向比较运算符为我们提供了更加直观、简洁的比较方式,使得代码更加优雅、更易于维护。通过提供一个统一的比较接口,它减少了代码量,提高了代码的可读性和可维护性。对于需要实现自定义类型比较功能的软件开发者来说,这个新特性无疑是一个巨大的福音。

💡 如果想阅读最新的文章,或者有技术问题需要交流和沟通,可搜索并关注微信公众号“希望睿智”。

相关文章:

  • UG数控编程入门:从基础到精通的全方位指南
  • 一个 python+tensorFlow训练1万张图片分类的简单直观例子( 回答由百度 AI 给出 )
  • 呆滞物料规范管理了,问题就好办了
  • 循环嵌套语句的实际应用(2)
  • 标准价与移动平均价简介
  • 让 AI 写高考作文丨10 款大模型 “交卷”,实力水平如何?
  • Nginx配置负载均衡
  • 近期面试HW中级蓝问题(非常详细)零基础入门到精通,收藏这一篇就够了
  • 计算机组成原理(一)
  • Mac电脑重置网络命令
  • Vue3【十】07使用ref创建基本类型的响应式数据以及ref和reactive区别
  • FM1202,FM020和利时备品
  • Docker的资源限制
  • 6.18云服务器大促盘点,错过一次,再等一年!
  • “GPT-4o深度解析:技术演进、能力评估与个人体验综述“
  • 【跃迁之路】【585天】程序员高效学习方法论探索系列(实验阶段342-2018.09.13)...
  • ES学习笔记(12)--Symbol
  • extract-text-webpack-plugin用法
  • JavaScript 是如何工作的:WebRTC 和对等网络的机制!
  • Java教程_软件开发基础
  • java正则表式的使用
  • PHP 使用 Swoole - TaskWorker 实现异步操作 Mysql
  • Spark RDD学习: aggregate函数
  • Zepto.js源码学习之二
  • 聊聊hikari连接池的leakDetectionThreshold
  • 数组大概知多少
  • 线性表及其算法(java实现)
  • 移动端唤起键盘时取消position:fixed定位
  • 栈实现走出迷宫(C++)
  • Mac 上flink的安装与启动
  • 阿里云IoT边缘计算助力企业零改造实现远程运维 ...
  • 曜石科技宣布获得千万级天使轮投资,全方面布局电竞产业链 ...
  • $emit传递多个参数_PPC和MIPS指令集下二进制代码中函数参数个数的识别方法
  • (20)目标检测算法之YOLOv5计算预选框、详解anchor计算
  • (2024,Flag-DiT,文本引导的多模态生成,SR,统一的标记化,RoPE、RMSNorm 和流匹配)Lumina-T2X
  • (3)STL算法之搜索
  • (done) 声音信号处理基础知识(2) (重点知识:pitch)(Sound Waveforms)
  • (八)c52学习之旅-中断实验
  • (二)换源+apt-get基础配置+搜狗拼音
  • (分享)一个图片添加水印的小demo的页面,可自定义样式
  • (附源码)python旅游推荐系统 毕业设计 250623
  • (附源码)springboot高校宿舍交电费系统 毕业设计031552
  • (未解决)jmeter报错之“请在微信客户端打开链接”
  • (学习日记)2024.04.10:UCOSIII第三十八节:事件实验
  • (一)搭建springboot+vue前后端分离项目--前端vue搭建
  • (转)Linq学习笔记
  • (转载)深入super,看Python如何解决钻石继承难题
  • .NET Core 网络数据采集 -- 使用AngleSharp做html解析
  • .NET Project Open Day(2011.11.13)
  • .net 按比例显示图片的缩略图
  • .NET 事件模型教程(二)
  • .NET 线程 Thread 进程 Process、线程池 pool、Invoke、begininvoke、异步回调
  • .net6使用Sejil可视化日志
  • .NET上SQLite的连接
  • .NET中winform传递参数至Url并获得返回值或文件