c++ 定义运算符<=> 和运算符 ==

560 阅读2分钟

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 天,点击查看活动详情