C++20 的三向比較(Three-way comparison)

三向比较(three-way comparison、参考)是C++20新增的一项新的运算子,他的形式是「<=>」;据说是由于外型的关系,所以也被称为「Spaceship Operator」。

而它的特色呢,则是可以针对两个变数进行比较,并透过一个回传值让使用者可以判断到底是大于、小于、还是等于;基本上是:

a < b 的话:(a <=> b) < 0
a > b 的话:(a <=> b) > 0
a 和b 相等或等价的话:(a <=> b) == 0

而实际上,根据变数的型别的不同,他可能会回传不同型别的结果来做区隔。

在这个新的header 档(文件)里面,就还有定义出三种不同的比较结果:

  • std::strong_ordering 比较结果有less、greater、equal、equivalent,后两者基本上相同
    整数型别的比较结果就是这种

  • std::weak_ordering 比较结果有 less、greater、equivalent
    和std::strong_ordering 的差别是只有equivalent 而没有equal

  • std::partial_ordering 比较结果有 less、greater、equivalent、unordered
    多了无法比较的状况,也就是unordered

    浮点数的比较结果会是这种,如果其中有一个是NaN 就会变成unordered

而虽然这三种型别的结果都可以用== 0、> 0、< 0来做判断,不过里也有提供命名的函式、来方便使用;包括了is_eq()、is_neq()、is_lt()、is_lteq()、is_gt()、is_gteq(),可以试需要使用。

下面就是一个简单的使用例子:

auto res = (1.0f <=> 1.0f);
if (std::is_eq(res))
  std::cout << "equal\n";
else
  std::cout << "not equal\n";

另外,按照强度的关系,也可以把较强的比较结果转换成较弱的结果,其关系就是:

strong_ordering -> weak_ordering -> partial_ordering

反过来则无法直接转换;下面是个简单的例子:

std::strong_ordering so = std::strong_ordering::equal;
std::weak_ordering wo = so;
std::partial_ordering po = so;
std::weak_ordering wo1 = po; //ERROR

而在Heresy 来看,定义三向比较的函式比较大的好处,在于如果针对自己定义的类别定义了operator<=>后,编译器就可以自动产生其他的比较函式、让这个类别可以做任意的比较了!

它会自动产生的比较函式包括了:==、!=、<、<=、>、>=这六个。

在最简单的状况下,只要加入一行、告诉编译器要使用预设的三向比较函式就可以了;下面就是一个例子:

struct SData
{
  int iVal = 0;
 
  auto operator<=>(const SData&) const = default;
};

如此一来,SData这个型别的资料,就可以在同型别的资料之间做各种比较,而不需要自己去各自定义不同的比较函式了。

预设的operator<=>会进行字典式的比较(lexicographical comparison),顺序是先比较base class(由左而右、深度优先)、然后再按照宣告顺序来比较non-static 的成员资料;而针对阵列,他应该也是会去依序比较内容。

这些比较会依序进行、在遇到不相等的时候就会停下来、回传比较的结果;所以在一般状况下,预设的比较方式应该算是可以直接拿来用的。

而如果预设的比较模式不符合需求的话,也可以自己定义比较的方法。

在《Default comparisons》,也提供了一些自订比较方法的例子。

像是如果只是想要修改比较顺序的话,可以写成:

struct Base {
  std::string zip;
  auto operator<=>(const Base&) const = default;
};
 
struct TotallyOrdered : Base {
  std::string tax_id;
  std::string first_name;
  std::string last_name;
 
public:
  // custom operator<=> because we want to compare last names first:
  std::strong_ordering operator<=>(const TotallyOrdered& that) const {
    if (auto cmp = (Base&)(*this) <=> (Base&)that; cmp != 0)
      return cmp;
    if (auto cmp = last_name <=> that.last_name; cmp != 0)
      return cmp;
    if (auto cmp = first_name <=> that.first_name; cmp != 0)
      return cmp;
    return tax_id <=> that.tax_id;
  }
  // ... non-comparison functions ...
};

他会先去用预设的方法比较基础型别Base,然后在按照last_name、first_name、tax_id的顺序来比较资料。

而如果有需要撰写进一步的比较方法,也是可以通过自己定义operator<=>的内容来达成的~

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

mikes zhang

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值