operator <=> (spaceship operator)

1. C++20 前如何定义比较运算符

C++20 之前,必须为一个类型定义六个操作符,以提供对象所有比较的支持。
例如,若要比较Value 类型的对象(具有整型ID),则须实现以下操作:

class Value
{
private:long id;...public:...// equality operators:bool operator== (const Value& rhs) const {return id == rhs.id; // basic check for equality}bool operator!= (const Value& rhs) const {return !(*this == rhs); // derived check}// relational operators:bool operator< (const Value& rhs) const {return id < rhs.id; // basic check for ordering}bool operator<= (const Value& rhs) const {return !(rhs < *this); // derived check}bool operator> (const Value& rhs) const {return rhs < *this; // derived check}bool operator>= (const Value& rhs) const {return !(*this < rhs); // derived check}
};

     尽管大多数操作符都是根据其他操作符定义的(都基于operator == 或operator <),但
这些定义很繁琐,而且会增加很多阅读上的混乱。
此外,对于实现良好的类型,可能需要更多的声明:
• 若操作符不能抛出,就用noexcept 声明
• 若操作符可以在编译时使用,则使用constexpr 声明
• 若构造函数不是显式的,则将操作符声明为“隐藏友元”(在类结构中与友元一起声明,以便
两个操作数都成为参数,并支持隐式类型转换)
• 声明带有[[nodiscard]] 的操作符,以便在返回值未使用时强制发出警告。

class Value {
private:long id;...public:constexpr Value(long i) noexcept // supports implicit type conversion: id{i} {}...// equality operators:[[nodiscard]] friend constexprbool operator== (const Value& lhs, const Value& rhs) noexcept {return lhs.id == rhs.id; // basic check for equality}[[nodiscard]] friend constexprbool operator!= (const Value& lhs, const Value& rhs) noexcept {return !(lhs == rhs); // derived check for inequality}// relational operators:[[nodiscard]] friend constexprbool operator< (const Value& lhs, const Value& rhs) noexcept {return lhs.id < rhs.id; // basic check for ordering}[[nodiscard]] friend constexprbool operator<= (const Value& lhs, const Value& rhs) noexcept {return !(rhs < lhs); // derived check}[[nodiscard]] friend constexprbool operator> (const Value& lhs, const Value& rhs) noexcept {return rhs < lhs; // derived check}[[nodiscard]] friend constexprbool operator>= (const Value& lhs, const Value& rhs) noexcept {return !(lhs < rhs); // derived check}
};

2.C++20 后如何定义比较运算符

== 与!= 操作符
为了检查是否相等,现在定义== 操作符就够了。
当编译器找不到表达式的匹配声明a!=b 时,编译器会重写表达式并查找!(a==b)。若这不起作
用,编译器也会尝试改变操作数的顺序,所以也会尝试!(b==a):

a != b // tries: a!=b, !(a==b), and !(b==a)

因此,对于TypeA 的a 和TypeB 的b,编译器将能够识别并编译

a != b

若需要的话,可以这样做
• 一个独立函数operator!=(TypeA, TypeB)
• 一个独立函数operator==(TypeA, TypeB)
• 一个独立函数operator==(TypeB, TypeA)
• 一个成员函数TypeA::operator!=(TypeB)
• 一个成员函数TypeA::operator==(TypeB)
• 一个成员函数TypeB::operator==(TypeA)

直接调用已定义的operator!= 是首选(但类型的顺序必须合适),更改操作数的顺序为最低的优
先级。同时拥有独立函数和成员函数会出现歧义错误。因此,

bool operator==(const TypeA&, const TypeB&);

或:

class TypeA {
public:
...
bool operator==(const TypeB&) const;
};

编译器可以进行编译:

MyType a;
MyType b;
...
a == b; // OK: fits perfectly
b == a; // OK, rewritten as: a == b
a != b; // OK, rewritten as: !(a == b)
b != a; // OK, rewritten as: !(a == b)

当重写将操作数转换为已定义成员函数的参数时,也可以对第一个操作数进行隐式类型转换。

<=> 操作符
对于所有的关系操作符,没有等价的规则说定义小于操作符就足够了。但现在,只需要定义新
的操作符<=> 即可。
事实上,以下内容足以让开发者使用所有可能的比较操作符:

#include <compare>
class Value {
private:long id;...
public:constexpr Value(long i) noexcept: id{i} {}...// enable use of all equality and relational operators:auto operator<=> (const Value& rhs) const = default;
};

通常,== 可以通过定义== 和!= 操作符来处理对象的相等性,而<=> 操作符通过定义关系操作
符来处理对象的顺序。若通过=default 声明操作符<=>,则可以使用了一个特殊的规则,即默认成
员操作符<=>:

class Value {
...
auto operator<=> (const Value& rhs) const = default;
};

生成对应的成员== 操作符,从而得到:

class Value {
...
auto operator<=> (const Value& rhs) const = default;
auto operator== (const Value& rhs) const = default; // implicitly generated
};

结果是两个操作符都使用了默认实现,逐个成员对象进行比较,所以类中成员的顺序很重要。
因此,

class Value {
...
auto operator<=> (const Value& rhs) const = default;
};

至此,我们得到了能够使用所有六个比较操作符所需的一切。
此外,即使将操作符声明为成员函数,也适用于生成的操作符:
• 若比较成员不抛出异常,则是noexcept
• 若可在编译时比较成员,则是constexpr
• 因为重写,还可以支持第一个操作数的隐式类型转换
通常情况下,== 和<=> 操作符处理不同但相关的事情:
• == 操作符定义相等性,可由相等操作符== 和!= 使用。
• <=> 操作符定义了排序,可以由关系操作符<、<=、> 和>= 使用。
注意,当默认或使用<=> 操作符时,必须包含头文件<compare>。

<=> 操作符的实现

为了更好地控制生成的比较操作符,可以自己定义== 和<=> 操作符。例如:

#include <compare>
class Value {
private:
    long id;
    ...
public:
    constexpr Value(long i) noexcept
    : id{i} {
    }
    ...
    // for equality operators:
    bool operator== (const Value& rhs) const {
        return id == rhs.id; // defines equality (== and !=)
    }
    // for relational operators:
    auto operator<=> (const Value& rhs) const {
        return id <=> rhs.id; // defines ordering (<, <=, >, and >=)
    }
};

可以指定哪个成员以哪个顺序重要或实现特殊行为。
这些基本操作符的工作方式是,若表达式使用其中一个比较操作符,并且没有找到匹配的直接
定义,则重写表达式,以便使用这些操作符。
与重写相等操作符调用相对应,重写也可能改变关系操作数的顺序,从而可能对第一个操作数
启用隐式类型转换。例如:

x <= y

没有找到<= 操作符的匹配定义,可以重写为

(x <=> y) <= 0

甚至

<= (y <=> x)

通过重写,<=> 操作符执行一个三向比较,生成一个可以与0 比较的值:
• 若x<=>y 的值等于0,则x 和y 等于或相等。
• 若x<=>y 小于0,则x 小于y.
• 若x<=>y 大于0,则x 大于y。
但请注意,<=> 操作符的返回类型不是整数值。返回类型是表示比较类别的类型,可以是强排
序、弱排序或偏排序,但这些类型支持与0 进行比较。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/18992.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

618精选编程书单:学好代码是用好大模型的基础

大家好&#xff0c;我是爱编程的喵喵。双985硕士毕业&#xff0c;现担任全栈工程师一职&#xff0c;热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。…

如何选择适合自己需求的云服务器

最近明月接了一个跨境电商的代维业务&#xff0c;发现他们的云服务器很有代表性&#xff0c;今天就以此为例给大家分享一下应该如何选择适合自己需求的云服务器。像明月这样专做代维业务的可以说什么云服务器都体验过了&#xff0c;也发现大家在选择自己的云服务器的时候有很大…

媒体查询检查设备特性的条件表达式的简单应用

一、media (max-width: 768px) 当屏幕宽度小于或等于768像素时&#xff0c;设置指定的CSS样式。 <!DOCTYPE html> <html lang"zh"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-wi…

加密资产私钥安全完整手册(一) ,bitget钱包为例

比特币和以太坊等加密货币的兴起开创了数字金融的新时代&#xff0c;但也带来了独特的安全挑战。这些代表现实世界价值的数字资产已成为黑客和窃贼的主要目标。为了安全地应对这种情况&#xff0c;了解私钥的基本概念至关重要。 私钥是加密货币所有权和安全性的基石。它们相当于…

VSCode小技巧,忽略不想格式化的代码行

零&#xff0e;格式化工具文档 1 . Black Ignoring sections功能 2 . autopep8 disabling-line-by-line功能&#xff1b;&#xff1b;–line-range选项 3 . Prettier prettier-ignore功能(例&#xff1a;适用于JS的// prettier-ignore&#xff0c;适用于CSS的/* prettier-igno…

HTML新春烟花盛宴

目录 写在前面 烟花盛宴 完整代码 修改文字

三步问题 | 动态规划

1.三步问题 题目连接&#xff1a;面试题 08.01. 三步问题 三步问题。有个小孩正在上楼梯&#xff0c;楼梯有n阶台阶&#xff0c;小孩一次可以上1阶、2阶或3阶。实现一种方法&#xff0c;计算小孩有多少种上楼梯的方式。结果可能很大&#xff0c;你需要对结果模1000000007。 2…

如何使用群联AI智能云防护来防御数据链路层

首先&#xff0c;需要明确的是&#xff0c;数据链路层的安全威胁和防护措施主要涉及到MAC地址管理、差错检测、加密和认证等方面。群联科技虽然可能没有在其官方文档中直接提到针对数据链路层的特定解决方案&#xff0c;但可以从其AI云防护技术的角度来推测一些可能的策略。 智…

C语言 指针——指针变量的定义、初始化及解引用

目录 指针 内存如何编址&#xff1f; 如何对变量进行寻址&#xff1f; 用什么类型的变量来存放变量的地址? 如何显示变量的地址?​编辑 使用未初始化的指针会怎样&#xff1f; NULL是什么&#xff1f; 如何访问指针变量指向的存储单元中的数据&#xff1f; 指针变量的…

APP原生开发与框架开发的优劣势

电话管家APP商用也有几年时间了&#xff0c;但是客户一直都有遇到一些问题。 为什么我们的APP老是要升级&#xff1f; 为什么有些手机使用体验不好&#xff1f; 为什么有些公司的APP几天就开发出来上线了&#xff1f; 为什么有些公司的APP那么便宜&#xff1f; 今天就来从…

家政预约小程序08服务详情

目录 1 创建页面2 创建URL参数3 配置数据详情组件4 从分类页跳转到详情页5 搭建详情页总结 现在我们的小程序已经在首页和分类页展示了服务的列表信息&#xff0c;当用户点击具体的内容的时候需要打开详情页&#xff0c;本篇介绍一下详情页的开发。 1 创建页面 打开应用编辑器…

中学生学人工智能系列:如何用AI学英语

经常有读者朋友给公众号《人工智能怎么学》留言咨询如何使用人工智能学习语文、数学、英语等科目。这些都是中学教师、中学生朋友及其家长们普遍关注的问题。仅仅使用留言回复的方式&#xff0c;不可能对这些问题做出具体和透彻的解答&#xff0c;因此本公众号近期将推出中学生…

如何在phpMy管理对Joomla后台的登录密码进行重置

本周有一个客户&#xff0c;购买Hostease的虚拟主机&#xff0c;询问我们的在线客服&#xff0c;如何在phpMy管理对Joomla后台的登录密码进行重置&#xff1f;我们为用户提供相关教程&#xff0c;用户很快解决了遇到的问题。在此&#xff0c;我们分享这个操作教程&#xff0c;希…

别再 pip install 了!一个绝佳的包管理器:pipx

在Python开发过程中&#xff0c;我们常常需要安装各种各样的工具库。有些库是项目级别的&#xff0c;比如Django或者Flask&#xff0c;而有些库是我们在整个系统中都可能用到的命令行工具&#xff0c;比如black、flake8、httpie等。对于后者&#xff0c;传统的pip安装方式可能会…

jenkins集成

jenkins是一款广泛使用的开源持续集成&#xff08;CI&#xff09;和持续交付&#xff08;CD&#xff09;工具&#xff0c;主要用于自动化构建、测试和部署软件。以下是关于如何集成Jenkins的详细介绍&#xff1a; 安装Jenkins&#xff1a; 要安装Jenkins&#xff0c;您需要按照…

DependencyCheck工具使用

1、工具下载地址 Releases jeremylong/DependencyCheck GitHub 2、工具使用 ./dependency-check.sh --disableRetireJS --disableNodeJS --project test -s /test/ -o /home/clog/test/report10 --noupdate

LeetCode题练习与总结:平衡二叉树--110

一、题目描述 给定一个二叉树&#xff0c;判断它是否是平衡二叉树。 示例 1&#xff1a; 输入&#xff1a;root [3,9,20,null,null,15,7] 输出&#xff1a;true示例 2&#xff1a; 输入&#xff1a;root [1,2,2,3,3,null,null,4,4] 输出&#xff1a;false示例 3&#xff1a…

【Java用法】java中计算两个时间差

java中计算两个时间差 不多说&#xff0c;直接上代码&#xff0c;可自行查看示例 package org.example.calc;import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.time.temporal.ChronoUnit;public class MinusTest {public static void…

97.网络游戏逆向分析与漏洞攻防-ui界面的设计-通过逆向分析确认角色信息

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 如果看不懂、不知道现在做的什么&#xff0c;那就跟着做完看效果&#xff0c;代码看不懂是正常的&#xff0c;只要会抄就行&#xff0c;抄着抄着就能懂了 内容…

分享几个PHP的webshell免杀思路

前言&#xff1a;网上的免杀思路有不少&#xff0c;不过大部分是基于混淆和加密的&#xff0c;我这里分享两个基于匿名函数、变量覆盖和反序列化的webshell思路&#xff0c;思路来源于深信服EDR的RCE漏洞。 ps&#xff1a;远程获取的时候&#xff0c;其实也可以用fopen读取远程…