C++20那些事之宇宙飛船運(yùn)算符
本節(jié)將引入C++20的另一個(gè)知識(shí)點(diǎn):宇宙飛船運(yùn)算符/三向比較運(yùn)算符。
三種排序
三向比較運(yùn)算符<=>又稱為宇宙飛船運(yùn)算符,返回值有三種排序,下面從gcc源碼角度來(lái)深入聊一下。
注:懶人版,本節(jié)示例已更新星球。
用法:<=>
#include <compare>
#include <iostream>
int main() {
auto c1 = 1.1 <=> 2.2;
auto c2 = -1 <=> 1;
std::cout << typeid(c1).name() << std::endl;
std::cout << typeid(c2).name() << std::endl;
}
輸出:
St16partial_ordering
St15strong_ordering
- 1.1 <=> 2.2:這是對(duì)兩個(gè)浮點(diǎn)數(shù)進(jìn)行比較。對(duì)于浮點(diǎn)數(shù),標(biāo)準(zhǔn)庫(kù)返回的是std::partial_ordering,因?yàn)楦↑c(diǎn)數(shù)有NaN值的存在,這使得它們之間的比較不是嚴(yán)格的全序。std::partial_ordering允許結(jié)果是<、>、==或者unordered。
我們可以使用gcc代碼靜態(tài)變量來(lái)查看partial_ordering到底是小于、大于、等于、無(wú)序:
static const partial_ordering less;
static const partial_ordering equivalent;
static const partial_ordering greater;
static const partial_ordering unordered;
如果我們強(qiáng)制轉(zhuǎn)換便會(huì)報(bào)錯(cuò):
comp.cc:6:36: error: conversion from 'std::partial_ordering' to non-scalar type 'std::strong_ordering' requested
6 | std::strong_ordering c1 = 1.1 <=> 2.2;
2. `-1 <=> 1`:這是對(duì)兩個(gè)整數(shù)進(jìn)行比較。對(duì)于整數(shù),標(biāo)準(zhǔn)庫(kù)返回的是`std::strong_ordering`,因?yàn)檎麛?shù)的比較是嚴(yán)格的全序關(guān)系,沒(méi)有不確定的情況。`std::strong_ordering`只會(huì)返回`<`、`>`或`==`。
同理,可以使用下面4個(gè)靜態(tài)成員。
static const strong_ordering less;
static const strong_ordering equal;
static const strong_ordering equivalent;
static const strong_ordering greater;
因此,c1的類型是std::partial_ordering,而c2的類型是std::strong_ordering,這也解釋了為什么輸出的類型不一樣。
除了partial_ordering、strong_ordering之外,<=>還可能返回weak_ordering,靜態(tài)成員為:
static const weak_ordering less;
static const weak_ordering equivalent;
static const weak_ordering greater;
equal與equivalent
在上面的三種ording可以看到對(duì)于等于出現(xiàn)了兩個(gè):equal與equivalent,這兩者有什么區(qū)別呢?
這里直接看cppreference,兩者之間沒(méi)有區(qū)別。然而,std::strong_ordering 是唯一定義相等的類別。所有其他類別僅定義等價(jià)。也正好驗(yàn)證了上面的靜態(tài)成員,對(duì)于string_ordering有兩個(gè),其他的只有equivalent。
如果比較在被比較的項(xiàng)目之間產(chǎn)生強(qiáng)排序,則等價(jià)和相等是相同的。之所以有兩個(gè)詞來(lái)表示它,是因?yàn)檫@對(duì)于其他類型的排序是不一樣的。弱和部分根本沒(méi)有相等性;它們只提供等價(jià)性。
等價(jià)意味著兩個(gè)對(duì)象可以比較相等。相等意味著更強(qiáng)的東西;如果它們比較相等,則可以在任何 const 用法中用一個(gè)替換另一個(gè):只要 a == b 為真,f(a) == f(b) 的屬性就為真,其中 f 表示僅讀取可通過(guò)參數(shù)的公共 const 成員訪問(wèn)的比較突出狀態(tài)的函數(shù)。如果類型的比較允許相等(這是強(qiáng)排序的要求),那么它也允許等價(jià)。因此,對(duì)于強(qiáng)排序比較,它們是相同的。
https://en.cppreference.com/w/cpp/utility/compare/strong_ordering
為什么使用三向比較運(yùn)算符?
三向比較運(yùn)算符(<=>)使得在一次操作中就能夠確定兩個(gè)值的排序關(guān)系,而傳統(tǒng)的比較運(yùn)算符則需要多次比較。
傳統(tǒng)比較運(yùn)算符的限制:
- 如果 a == b 為假,你無(wú)法知道 a < b 還是 a > b。
- 如果 a != b 為真,你無(wú)法知道 a < b 還是 a > b。
- 如果 a < b 為假,你無(wú)法知道 a == b 還是 a > b。
- 如果 a > b 為假,你無(wú)法知道 a == b 還是 a < b。
- 如果 a <= b 為真,你無(wú)法知道 a == b 還是 a < b。
- 如果 a >= b 為真,你無(wú)法知道 a == b 還是 a > b。
這些限制表明,傳統(tǒng)的比較運(yùn)算符不能一次性確定兩個(gè)值的完全關(guān)系,而是需要多次比較來(lái)獲得完整的結(jié)果。