operator <=> (spaceship operator)

2024-05-29 21:20
文章标签 operator spaceship

本文主要是介绍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 进行比较。

这篇关于operator <=> (spaceship operator)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1014674

相关文章

Flink 原理与实现:Operator Chain原理

硬刚大数据系列文章链接: 2021年从零到大数据专家的学习指南(全面升级版) 2021年从零到大数据专家面试篇之Hadoop/HDFS/Yarn篇 2021年从零到大数据专家面试篇之SparkSQL篇 2021年从零到大数据专家面试篇之消息队列篇 2021年从零到大数据专家面试篇之Spark篇 2021年从零到大数据专家面试篇之Hbase篇

Flink: 两个递归彻底搞懂operator chain

《2021年最新版大数据面试题全面开启更新》 operator chain是指将满足一定条件的operator 链在一起,放在同一个task里面执行,是Flink任务优化的一种方式,在同一个task里面的operator的数据传输变成函数调用关系,这种方式减少数据传输过程。常见的chain例如:source->map->filter,这样的任务链可以chain在一起,那么其内部是如何决定

C++ std::set<,> operator怎么用

std::set 不重复key默认less排序 STL中的关联容器: std::set template<class Key,class Compare = std::less<Key>,class Allocator = std::allocator<Key>> class set; std::set 是关联容器,含有 Key 类型对象的已排序集。 它的key就是value

Java Operator SDK

Java Operator SDK 生成项目骨架快速入门模式和最佳实践使用示例Operators实现示例OperatorQuarkusSpring Boot Operators 代表Kubernetes管理集群和非集群资源。这个Java Operator SDK (JOSDK) 旨在通过使用一个对Java开发人员来说应该感觉自然的API,使编写Kubernetes操作员变得尽可能

0基础学习Python路径(40)operator模块

operator 模块 operator 模块提供了一套与 Python 的内置运算符对应的高效率函数。 函数的种类 函数包含的种类有:对象的比较运算、逻辑运算、数学运算和序列运算 比较运算 运算函数语法小于lt(a, b)a < b小于等于le(a, b)a <= b大于gt(a, b)a > b大于等于ge(a, b)a >= b等于eq(a, b)a == b不等于ne(a, b)

孙鑫视频学习:“operator +=” 不明确的问题解决方法

在基于单文档应用程序的MFC程序中,在OnChar函数中使用m_strLine+=nChar时,出现了error C2593:“operator +=”不明确的错误,如下解决方法,亲测可用:   将m_strLine+=nChar改为m_strLine+=char(nChar)或m_strLine+=(char)nChar   因为:在OnChar函数的参数中,nChar是UINT类型的。

C++map容器中operator[ ]的实现原理

目录 一、operator[ ]函数介绍 二、insert函数介绍 三、operator[ ]函数实现原理 四、operator[ ]函数功能 一、operator[ ]函数介绍 mapped_type& operator[] (const key_type& k); 在map容器中存储的是一个键值对value_type,其本质是pair<const key_type,

new 和operator new

参考 1、http://blog.csdn.net/wudaijun/article/details/9273339 2、http://www.cnblogs.com/luxiaoxun/archive/2012/08/10/2631812.html new 、operator new 和 placement new <—-> new( (void*)pBuf) ClassObj(obj)

Clickhouse集群化(四)使用clickhouse-operator部署clickhouse集群

clickhouse operator实际下就是帮助我们自动化的生产一些clickhouse配置文件信息,在目录/etc/clickhouse-server/的config.d conf.d users.d 1.1. 部署clickhouse operateor 下载clickhouse-operator.yaml文件 wget https://raw.githubusercontent.c

C++函数对象operator()

https://blog.csdn.net/xgf415/article/details/52966475