c++ 定义运算符<=> 和运算符 ==
可以为数据类型定义运算符 < = > 和运算符 = = :
-
作为带有一个参数的成员函数
-
或者一个带有两个参数的独立函数
在类或数据结构中(作为成员或友元函数),两个操作符都可以声明为默认值,使用=default。成员函数必须接受第二个形参作为const Ivalue引用(const &)。友元函数也可以按值接受两个参数。
对于operator<=>和operator==的默认定义:
-
如果比较成员保证不抛出,则操作符为noexcept。
-
如果在编译时可以比较成员,则操作符为constexpr。
默认运算符 < = >
当且仅当operator<=>成员定义为默认值时,则根据定义也定义了相应的operator==成员。采用了所有方面(可见性、虚拟性、属性、需求等)。例如:
template<typename
T> class Type {
---
public:
[[nodiscard]] virtual std::strong_ordering
operator<=>(const Type&) const requires(!std::same_as<T,bool>) = default;
};
等同于:
template<typename T> class Type {
public:
[[nodiscard]] virtual std::strong_ordering
operator<=>(const Type&) const requires(!std::same_as<T,bool>) = default;
[[nodiscard]] virtual bool
operator== (const Type&) const requires(!std::same_as<T,bool>) = default; };
例如,下面的代码足以支持Coord类型对象的所有6个比较操作符
#include <compare>
struct Coord{
double x{};
double y{};
double z{};
auto operator<=>(const Coord&) const =default; };
再次注意,成员函数必须是const,形参必须声明为const Ivalue引用(const&)。您可以按照如下方式使用此数据结构
#include "coord.hpp"
#include <iostream>
#include <algorithm>
int main()
{
std::vector<Coord> coll{ {0,5,5},{5,0,0},{3,5,5},
{3,0,0},{3,5,7}};
std::sort(coll.begin(),coll.end());
for (const auto& elem : coll) {
std::cout<<elem.x<<'/'<<elem.y<<'/'<<elem.z<<'\n';
}
}
该程序有以下输出:
0/5/5
3/0/0
3/5/5
3/5/7
5/0/0
默认操作符<=>和继承
如果操作符<=>是默认的,那么您有一个基类,并且调用其中一个关系操作符,则会发生以下情况:
-
如果定义了基类操作符<=>,则调用该操作符。
-
否则,调用operator==和operator<来决定是否(从基类的角度)
- 对象相等/等价(运算符==产生 true)
- 对象小于或大于
- 对象无序(仅在选中部分排序时)
在这种情况下,调用这些操作符的默认操作符<=>的返回类型不能是自动的。例如,考虑以下声明
struct Base {
bool operator==(const Base&) const;
bool operator<(const Base&) const;
};
struct Derived : public Base {
std::strong_ordering operator<=> (const Derived&) const =default;
};
然后:
Derived d1,d2;
d1>d2;//calls Base::operator==and possibly Base::operator<
如果operator==的结果为真,我们就知道>的结果为假,就是这样。否则,调用操作符<来找出表达式是真还是假。
struct Derived : public Base {
std::partia1_ordering operator<=> (const Derived&) const =default; };
编译器可能会调用操作符<甚至两次,以确定是否存在任何顺序。与
struct Base {
bool operator==(const Base&) const;
bool operator<(const Base&) const;
};
struct Derived : public Base{
auto operator<=> (const Derived&) const =default; };
译器不编译使用关系操作符的任何调用,因为它不能确定基类具有哪个排序类别。在这种情况下,基类中也需要操作符<=>。
然而,检查相等性工作,因为在派生操作符==被自动声明为等价于以下
struct Derived : public Base {
auto operator<=> (const Derived&) const = default;
bool operator==(const Derived&) const =default; };
所以我们有下面的行为
Derived d1,d2;
d1>d2; //错误:无法推断运算符的比较类别
d1 !=d2; //OK(注意:只尝试operator<=> und Base::operator==一个总线类)
相等性检查总是只使用基类的operator==(不过,它可能是根据默认操作符<=>生成的)。任何操作符<或操作符!基类中的=将被忽略。
开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 N 天,点击查看活动详情”