欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

c++20引入的三路比較操作符<=>

 更新時(shí)間:2025年06月27日 10:51:14   作者:洞陽  
本文主要介紹了c++20引入的三路比較操作符<=>,返回strong_ordering、weak_ordering和partial_ordering三種類型,下面就來具體介紹一下,感興趣的可以了解一下

一、簡(jiǎn)介

c++20引入了三路比較操作符(或者三向比較)<=>(three-way comparison operator),也叫太空船(spaceship)操作符。

<=>也是一個(gè)二元關(guān)系運(yùn)算符,但它不像其他二元比較操作符那樣返回類型是布爾類型,而是根據(jù)用戶指明的三種類型之一:partial_ordering、weak_ordering和strong_ordering,定義于標(biāo)準(zhǔn)庫頭文件<compare>中,默認(rèn)為strong_ordering類型。

  • 偏序partial_ordering表達(dá)了比較關(guān)系中的偏序關(guān)系,即給定類的任意兩個(gè)對(duì)象不一定可比較。例如給定一棵對(duì)象樹,假設(shè)父節(jié)點(diǎn)比子節(jié)點(diǎn)大,<=>得到的結(jié)果將為greater,但不是任意兩個(gè)節(jié)點(diǎn)都可比較,此時(shí)它們的關(guān)系為unordered。對(duì)于偏序關(guān)系的排序,使用拓?fù)渑判蛩惴▽@得正確的結(jié)果。
  • 弱序weak_ordering表達(dá)了比較關(guān)系中的全序關(guān)系,即給定類的任意兩個(gè)對(duì)象都能比較,將既不大于也不小于的關(guān)系定義為等價(jià)(equivalent)關(guān)系。假設(shè)長(zhǎng)方形類按照面積比較就是弱序關(guān)系,長(zhǎng)寬分別為2和6的矩形與長(zhǎng)寬分別為3和4的比較,面積都為12(既不大于也不小于)?,那么它們是等價(jià)的,但不相等是因?yàn)榭梢酝ㄟ^長(zhǎng)寬區(qū)分出來它們不一樣。標(biāo)準(zhǔn)庫中的std::sort要求關(guān)系至少為弱序的才能正確工作。
  • 強(qiáng)序strong_ordering與弱序一樣,當(dāng)對(duì)等價(jià)關(guān)系進(jìn)行了約束即為相等(equal)關(guān)系??紤]正方形類按照面積比較就是強(qiáng)序關(guān)系,因?yàn)槊娣e一樣的正方形無法像長(zhǎng)方形那樣通過外表能區(qū)分出來,即它們是相等的。一些查找算法要求關(guān)系為強(qiáng)序才能正確工作。

此外<=>的結(jié)果也與字符串比較函數(shù)strcmp類似,能夠通過正負(fù)判斷關(guān)系:當(dāng)結(jié)果大于0表示大于關(guān)系,等于0表示等價(jià)、等于關(guān)系,小于0表示小于關(guān)系。

顧名思義,三向比較就是在形如lhs <=> rhs的表達(dá)式中,兩個(gè)比較的操作數(shù)lhs和rhs通過<=>比較可能產(chǎn)生3種結(jié)果,該結(jié)果可以和0比較,小于0、等于0或者大于0分別對(duì)應(yīng)lhs < rhs、lhs == rhs和lhs > rhs。舉例來說:

#include<iostream>

int main(int argc,char* argv[]){
    bool b = 7<=>11 <0;
    std::cout<<std::boolalpha<<b<<std::endl;
    b = 7<=>11 ==0;
    std::cout<<std::boolalpha<<b<<std::endl;
    b = 7<=>11 >0;
    std::cout<<std::boolalpha<<b<<std::endl;
    b = 7<=>7 ==0;
    std::cout<<std::boolalpha<<b<<std::endl;
    return 0;
}

輸出:

true
false
false
true

請(qǐng)注意,運(yùn)算符<=>的返回值只能與0和自身類型來比較,如果同其他數(shù)值比較,編譯器會(huì)報(bào)錯(cuò):

#include<iostream>

int main(int argc,char* argv[]){
    bool b = 7<=>11 <100;//編譯失敗,<=>的結(jié)果不能與除0以外的數(shù)值比較
    std::cout<<std::boolalpha<<b<<std::endl;
    return 0;
}

二、三向比較的返回類型

<=>的返回結(jié)果并不是一個(gè)普通類型,根據(jù)標(biāo)準(zhǔn)三向比較會(huì)返回3種類型,分別為std::strong_ordering、std::weak_ordering以及std::partial_ordering,而這3種類型又會(huì)分為有3~4種最終結(jié)果。

2.1 std::strong_ordering

std::strong_ordering類型有3種比較結(jié)果,分別為std::strong_ ordering::less、std::strong_ordering::equal以及std::strong_ ordering::greater。表達(dá)式lhs <=> rhs分別表示lhs < rhs、lhs == rhs以及l(fā)hs > rhs。std::strong_ordering類型的結(jié)果強(qiáng)調(diào)的是strong的含義,表達(dá)的是一種可替換性,簡(jiǎn)單來說,若lhs == rhs,那么在任何情況下rhs和lhs都可以相互替換,也就是fx(lhs) == fx(rhs)。

對(duì)于基本類型中的int類型,三向比較返回的是std::strong_ordering,例如:

用MSVC編譯運(yùn)行以上代碼,會(huì)在輸出窗口顯示class std::strong_ ordering,刻意使用MSVC是因?yàn)樗膖ypeid(x).name()可以輸出友好可讀的類型名稱。

對(duì)于有復(fù)雜結(jié)構(gòu)的類型,std::strong_ordering要求其數(shù)據(jù)成員和基類的三向比較結(jié)果都為std::strong_ordering。例如:

#include<iostream>

struct B{
    int a;
    long b;
    auto operator <=> (const B&) const = default;
};

struct D : B{
    short c;
    auto operator <=> (const D&) const = default;
};

int main(int argc,char* argv[]){
    D x1,x2;
    std::cout<<typeid(decltype(x1 <=> x2)).name()<<std::endl;
}

上面這段代碼用MSVC編譯運(yùn)行會(huì)輸出class std::strong_ordering。

請(qǐng)注意,默認(rèn)情況下自定義類型是不存在三向比較運(yùn)算符函數(shù)的,需要用戶顯式默認(rèn)聲明,比如在結(jié)構(gòu)體B和D中聲明auto operator <=> (const B&) const = default;和auto operator <=> (const D&)const = default;。

 如果刪除基類的<=>運(yùn)算符,派生類顯式定義的<=>將被刪除。

如果刪除派生類的<=>,保留基類的<=>,還可以運(yùn)行。

 對(duì)結(jié)構(gòu)體B而言,由于int和long的比較結(jié)果都是std::strong_ordering,因此結(jié)構(gòu)體B的三向比較結(jié)果也是std::strong_ordering。同理,對(duì)于結(jié)構(gòu)體D,其基類和成員的比較結(jié)果是std::strong_ordering,D的三向比較結(jié)果同樣是std::strong_ordering。

另外,明確運(yùn)算符的返回類型,使用std::strong_ ordering替換auto也是沒問題的。

2.2 std::weak_ordering

std::weak_ordering類型也有3種比較結(jié)果,分別為std::weak_ ordering::less、std::weak_ordering::equivalent以及std::weak_ ordering::greater。std::weak_ordering的含義正好與std::strong_ ordering相對(duì),表達(dá)的是不可替換性。即若有l(wèi)hs == rhs,則rhs和lhs不可以相互替換,也就是fx(lhs) != fx(rhs)。這種情況在基礎(chǔ)類型中并沒有,但是它常常發(fā)生在用戶自定義類中,比如一個(gè)大小寫不敏感的字符串類:

#include <compare>
#include <string>
#include <iostream>

int ci_compare(const char* s1, const char* s2)
{
  while (tolower(*s1) == tolower(*s2++)) {
       if (*s1++ == '\0') {
            return 0;
       }
  }
  return tolower(*s1) - tolower(*--s2);
}

class CIString {
public:
  CIString(const char *s) : str_(s) {}

  std::weak_ordering operator<=>(const CIString& b) const {
       return ci_compare(str_.c_str(), b.str_.c_str()) <=> 0;//strong_ordering返回為weak_ordering類型,實(shí)際上發(fā)生了類型轉(zhuǎn)換
  }
private:
  std::string str_;
};

int main(int argc,char* argv[])
{
    auto res = 'a'<=>'a';
    std::cout << typeid(res).name()<<std::endl;      //strong_ordering
    std::cout << typeid(res<=>0).name()<<std::endl;  //strong_ordering
    std::cout << typeid( ((std::weak_ordering)res) ).name()<<std::endl; //strong_ordering可以轉(zhuǎn)為weak_ordering
    
    CIString s1{ "HELLO" }, s2{"hello"};
    std::cout << std::boolalpha << (s1 <=> s2 == 0)<<std::endl; // 輸出為true
    std::cout << typeid(s1<=>s2).name()<<std::endl;  //weak_ordering
    return 0;
}

以上代碼實(shí)現(xiàn)了一個(gè)簡(jiǎn)單的大小寫不敏感的字符串類,它對(duì)于s1和s2的比較結(jié)果是std::weak_ordering::equivalent,表示兩個(gè)操作數(shù)是等價(jià)的,但是它們不是相等的也不能相互替換。當(dāng)std::weak_ordering和std::strong_ ordering同時(shí)出現(xiàn)在基類和數(shù)據(jù)成員的類型中時(shí),該類型的三向比較結(jié)果是std::weak_ordering,例如:

#include <compare>
#include <string>
#include <iostream>

int ci_compare(const char* s1, const char* s2)
{
  while (tolower(*s1) == tolower(*s2++)) {
       if (*s1++ == '\0') {
            return 0;
       }
  }
  return tolower(*s1) - tolower(*--s2);
}

class CIString {
public:
  CIString(const char *s) : str_(s) {}

  std::weak_ordering operator<=>(const CIString& b) const {
       return ci_compare(str_.c_str(), b.str_.c_str()) <=> 0;//strong_ordering返回為weak_ordering類型,實(shí)際上發(fā)生了類型轉(zhuǎn)換
  }
private:
  std::string str_;
};

struct B{
    int a=0;
    long b=0;
    std::strong_ordering operator <=> (const B&) const = default;
};

struct D : B{
    CIString c{""};
    auto operator <=> (const D&) const = default;
};

int main(int argc,char* argv[])
{
    D w1,w2;
    std::cout << std::boolalpha << (w1 <=> w2 == 0)<<std::endl; // 輸出為true
    std::cout << std::boolalpha << (w1 <=> w2 == std::weak_ordering::equivalent)<<std::endl; // 輸出為true
    std::cout << typeid(w1<=>w2).name()<<std::endl;  //weak_ordering
    return 0;
}

用MSVC編譯運(yùn)行上面這段代碼會(huì)輸出class std::weak_ordering,因?yàn)镈中的數(shù)據(jù)成員CIString的三向比較結(jié)果為std::weak_ordering。請(qǐng)注意,如果顯式聲明默認(rèn)三向比較運(yùn)算符函數(shù)為std::strong_ordering operator <=> (const D&) const = default;,那么一定會(huì)遭遇到一個(gè)編譯錯(cuò)誤。

2.3 std::partial_ordering

std::partial_ordering類型有4種比較結(jié)果,分別為std::partial_ ordering::less、std::partial_ordering::equivalent、std::partial_ ordering::greater以及std::partial_ordering::unordered。std:: partial_ordering約束力比std::weak_ordering更弱,它可以接受當(dāng)lhs == rhs時(shí)rhs和lhs不能相互替換,同時(shí)它還能給出第四個(gè)結(jié)果std::partial_ordering::unordered,表示進(jìn)行比較的兩個(gè)操作數(shù)沒有關(guān)系。比如基礎(chǔ)類型中的浮點(diǎn)數(shù):

#include <iostream>

int main(int argc,char* argv[])
{
    std::cout << typeid(decltype(7.7 <=> 11.1)).name();//輸出partial_ordering
    return 0;
}

用MSVC編譯運(yùn)行以上代碼會(huì)輸出class std::partial_ordering。之所以會(huì)輸出class std::partial_ordering而不是std::strong_ordering,是因?yàn)楦↑c(diǎn)的集合中存在一個(gè)特殊的NaN,它和其他浮點(diǎn)數(shù)值是沒關(guān)系的:

#include <iostream>

int main(int argc,char* argv[])
{
    std::cout<<std::boolalpha<< ((0.0/0.0 <=> 1.0) == std::partial_ordering::unordered);//輸出true
    return 0;
}

這段代碼編譯輸出的結(jié)果為true。

當(dāng)std::weak_ordering和std:: partial_ordering同時(shí)出現(xiàn)在基類和數(shù)據(jù)成員的類型中時(shí),該類型的三向比較結(jié)果是std::partial_ordering,例如:

#include <compare>
#include <string>
#include <iostream>
 
int ci_compare(const char* s1, const char* s2)
{
  while (tolower(*s1) == tolower(*s2++)) {
       if (*s1++ == '\0') {
            return 0;
       }
  }
  return tolower(*s1) - tolower(*--s2);
}
 
class CIString {
public:
  CIString(const char *s) : str_(s) {}
 
  std::weak_ordering operator<=>(const CIString& b) const {
       return ci_compare(str_.c_str(), b.str_.c_str()) <=> 0;//strong_ordering返回為weak_ordering類型,實(shí)際上發(fā)生了類型轉(zhuǎn)換
  }
private:
  std::string str_;
};
 
struct B{
    int a=0;
    long b=0;
    std::strong_ordering operator <=> (const B&) const = default;
};
 
struct D : B{
    CIString c{""};
    float u=0.0;
    auto operator <=> (const D&) const = default;
};
 
int main(int argc,char* argv[])
{
    D w1,w2;
    std::cout << std::boolalpha << (w1 <=> w2 == 0)<<std::endl; // 輸出為true
    std::cout << std::boolalpha << (w1 <=> w2 == std::partial_ordering::equivalent)<<std::endl; // 輸出為true
    std::cout << typeid(w1<=>w2).name()<<std::endl;  //partial_ordering
    return 0;
}

用MSVC編譯運(yùn)行以上代碼會(huì)輸出class std::partial_ordering,因?yàn)镈中的數(shù)據(jù)成員u的三向比較結(jié)果為std::partial_ordering,同樣,顯式聲明為其他返回類型也會(huì)讓編譯器報(bào)錯(cuò)。在C++20的標(biāo)準(zhǔn)庫中有一個(gè)模板元函數(shù)std::common_comparison_category,它可以幫助我們?cè)谝粋€(gè)類型合集中判斷出最終三向比較的結(jié)果類型,當(dāng)類型合集中存在不支持三向比較的類型時(shí),該模板元函數(shù)返回void。

再次強(qiáng)調(diào)一下,std::strong_ordering、std::weak_ordering和`std::partial_ordering`只能與`0`和類型自身比較。深究其原因,是這3個(gè)類只實(shí)現(xiàn)了參數(shù)類型為自身類型和`nullptr_t的比較運(yùn)算符函數(shù)。

三、對(duì)基礎(chǔ)類型的支持

  • 3.1.對(duì)兩個(gè)算術(shù)類型的操作數(shù)進(jìn)行一般算術(shù)轉(zhuǎn)換,然后進(jìn)行比較。其中整型的比較結(jié)果為std::strong_ordering,浮點(diǎn)型的比較結(jié)果為std::partial_ordering。例如7 <=> 11.1中,整型7會(huì)轉(zhuǎn)換為浮點(diǎn)類型,然后再進(jìn)行比較,最終結(jié)果為std::partial_ordering類型。
  • 3.2.對(duì)于無作用域枚舉類型和整型操作數(shù),枚舉類型會(huì)轉(zhuǎn)換為整型再進(jìn)行比較,無作用域枚舉類型無法與浮點(diǎn)類型比較:
enum color {
  red
};

auto r = red <=> 11;   //編譯成功
auto r = red <=> 11.1; //編譯失敗
  • 3.3.對(duì)兩個(gè)相同枚舉類型的操作數(shù)比較結(jié)果,如果枚舉類型不同,則無法編譯。
  • 3.4.對(duì)于其中一個(gè)操作數(shù)為bool類型的情況,另一個(gè)操作數(shù)必須也是bool類型,否則無法編譯。比較結(jié)果為std::strong_ordering。
  • 3.5.不支持作比較的兩個(gè)操作數(shù)為數(shù)組的情況,會(huì)導(dǎo)致編譯出錯(cuò),例如:
int arr1[5];
int arr2[5];
auto r = arr1 <=> arr2; // 編譯失敗
  • 3.6.對(duì)于其中一個(gè)操作數(shù)為指針類型的情況,需要另一個(gè)操作數(shù)是同樣類型的指針,或者是可以轉(zhuǎn)換為相同類型的指針,比如數(shù)組到指針的轉(zhuǎn)換、派生類指針到基類指針的轉(zhuǎn)換等,最終比較結(jié)果為std::strong_ordering:
char arr1[5];
char arr2[5];
char* ptr = arr2;
auto r = ptr <=> arr1;

上面的代碼可以編譯成功,若將代碼中的arr1改寫為int arr1[5],則無法編譯,因?yàn)閕nt [5]無法轉(zhuǎn)換為char *。如果將char * ptr = arr2;修改為void * ptr = arr2;,代碼就可以編譯成功了。

四、自動(dòng)生成的比較運(yùn)算符函數(shù)

4.1 std::rel_ops的作用

標(biāo)準(zhǔn)庫中提供了一個(gè)名為std::rel_ops的命名空間,在用戶自定義類型已經(jīng)提供了==運(yùn)算符函數(shù)和<運(yùn)算符函數(shù)的情況下,幫助用戶實(shí)現(xiàn)其他4種運(yùn)算符函數(shù),包括!=、>、<=和>=。

 代碼:

#include <compare>
#include <string>
#include <iostream>
#include <utility>
 
int ci_compare(const char* s1, const char* s2)
{
  while (tolower(*s1) == tolower(*s2++)) {
       if (*s1++ == '\0') {
            return 0;
       }
  }
  return tolower(*s1) - tolower(*--s2);
}
 
class CIString2 {
public:
  CIString2(const char* s) : str_(s) {}

  bool operator < (const CIString2& b) const {
       return ci_compare(str_.c_str(), b.str_.c_str()) < 0;
  }
  
  bool operator== (const CIString2& b) const {
       return ci_compare(str_.c_str(), b.str_.c_str()) == 0;
  }
private:
  std::string str_;
};


int main(int argc,char* argv[])
{
    using namespace std::rel_ops;
    CIString2 s1( "hello" ), s2( "world" );
    bool r = true;
    r = s1 == s2;
    std::cout<<std::boolalpha<<r<<std::endl;
    r = s1 != s2;
    std::cout<<std::boolalpha<<r<<std::endl;
    r = s1 > s2;
    std::cout<<std::boolalpha<<r<<std::endl;
    r = s1 >= s2;
    std::cout<<std::boolalpha<<r<<std::endl;
    r = s1 < s2;
    std::cout<<std::boolalpha<<r<<std::endl;
    r = s1 <= s2;
    std::cout<<std::boolalpha<<r<<std::endl;
    return 0;
}

輸出:

false
true
false
false
true
true

4.2 使用<=>

不過因?yàn)镃++20標(biāo)準(zhǔn)有了三向比較運(yùn)算符的關(guān)系,所以不推薦上面這種做法了。C++20標(biāo)準(zhǔn)規(guī)定,如果用戶為自定義類型聲明了三向比較運(yùn)算符,那么編譯器會(huì)為其自動(dòng)生成<、>、<=和>=這4種運(yùn)算符函數(shù)。對(duì)于CIString我們可以直接使用這4種運(yùn)算符函數(shù):

#include <compare>
#include <string>
#include <iostream>
#include <utility>
 
int ci_compare(const char* s1, const char* s2)
{
  while (tolower(*s1) == tolower(*s2++)) {
       if (*s1++ == '\0') {
            return 0;
       }
  }
  return tolower(*s1) - tolower(*--s2);
}
 
class CIString {
public:
  CIString(const char *s) : str_(s) {}
  
//   bool operator== (const CIString& b) const {
//       return ci_compare(str_.c_str(), b.str_.c_str()) == 0;
//   }
 
  std::weak_ordering operator<=>(const CIString& b) const {
       return ci_compare(str_.c_str(), b.str_.c_str()) <=> 0;//strong_ordering返回為weak_ordering類型,實(shí)際上發(fā)生了類型轉(zhuǎn)換
  }
private:
  std::string str_;
};

int main(int argc,char* argv[])
{
    CIString s1( "hello" ), s2( "world" );
    bool r = true;
    // r = s1 == s2;
    // std::cout<<std::boolalpha<<r<<std::endl;
    // r = s1 != s2;
    // std::cout<<std::boolalpha<<r<<std::endl;
    r = s1 > s2;
    std::cout<<std::boolalpha<<r<<std::endl;
    r = s1 >= s2;
    std::cout<<std::boolalpha<<r<<std::endl;
    r = s1 < s2;
    std::cout<<std::boolalpha<<r<<std::endl;
    r = s1 <= s2;
    std::cout<<std::boolalpha<<r<<std::endl;
    return 0;
}

輸出

false
false
true
true

那么這里就會(huì)產(chǎn)生一個(gè)疑問,很明顯三向比較運(yùn)算符能表達(dá)兩個(gè)操作數(shù)是相等或者等價(jià)的含義,為什么標(biāo)準(zhǔn)只允許自動(dòng)生成4種運(yùn)算符函數(shù),卻不能自動(dòng)生成==和=!這兩個(gè)運(yùn)算符函數(shù)呢?實(shí)際上這里存在一個(gè)嚴(yán)重的性能問題。在C++20標(biāo)準(zhǔn)擬定三向比較的早期,是允許通過三向比較自動(dòng)生成6個(gè)比較運(yùn)算符函數(shù)的,而三向比較的結(jié)果類型也不是3種而是5種,多出來的兩種分別是std::strong_ equality和std::weak_equality。但是在提案文檔p1190中提出了一個(gè)嚴(yán)重的性能問題。簡(jiǎn)單來說,假設(shè)有一個(gè)結(jié)構(gòu)體:

struct S {
    std::vector<std::string> names;
    auto operator<=>(const S &) const = default;
};

它的三向比較運(yùn)算符的默認(rèn)實(shí)現(xiàn)這樣的:

template<typename T>
std::strong_ordering operator<=>(const std::vector<T>& lhs, const std::vector<T> & rhs) 
{
    size_t min_size = min(lhs.size(), rhs.size());
    for (size_t i = 0; i != min_size; ++i) {
        if (auto const cmp = std::compare_3way(lhs[i], rhs[i]); cmp != 0) {
            return cmp;
        }
    }
    return lhs.size() <=> rhs.size();
}

這個(gè)實(shí)現(xiàn)對(duì)于<和>這樣的運(yùn)算符函數(shù)沒有問題,因?yàn)樾枰容^容器中的每個(gè)元素。但是==運(yùn)算符就顯得十分低效,對(duì)于==運(yùn)算符高效的做法是先比較容器中的元素?cái)?shù)量是否相等,如果元素?cái)?shù)量不同,則直接返回false:

template<typename T>
bool operator==(const std::vector<T>& lhs, const std::vector<T>& rhs)
{
    const size_t size = lhs.size();
    if (size != rhs.size()) {
        return false;
    }

    for (size_t i = 0; i != size; ++i) {
        if (lhs[i] != rhs[i]) {
            return false;
        }
    }
    return true;
}

想象一下,如果標(biāo)準(zhǔn)允許用三向比較的算法自動(dòng)生成==運(yùn)算符函數(shù)會(huì)發(fā)生什么事情,很多舊代碼升級(jí)編譯環(huán)境后會(huì)發(fā)現(xiàn)運(yùn)行效率下降了,尤其是在容器中元素?cái)?shù)量眾多且每個(gè)元素?cái)?shù)據(jù)量龐大的情況下。很少有程序員會(huì)注意到三向比較算法的細(xì)節(jié),導(dǎo)致這個(gè)性能問題難以排查。基于這種考慮,C++委員會(huì)修改了原來的三向比較提案,規(guī)定聲明三向比較運(yùn)算符函數(shù)只能夠自動(dòng)生成4種比較運(yùn)算符函數(shù)。由于不需要負(fù)責(zé)判斷是否相等,因此std::strong_equality和std::weak_ equality也退出了歷史舞臺(tái)。對(duì)于==和!=兩種比較運(yùn)算符函數(shù),只需要多聲明一個(gè)==運(yùn)算符函數(shù),!=運(yùn)算符函數(shù)會(huì)根據(jù)前者自動(dòng)生成:

#include <compare>
#include <string>
#include <iostream>
#include <utility>
 
int ci_compare(const char* s1, const char* s2)
{
  while (tolower(*s1) == tolower(*s2++)) {
       if (*s1++ == '\0') {
            return 0;
       }
  }
  return tolower(*s1) - tolower(*--s2);
}
 
class CIString {
public:
  CIString(const char *s) : str_(s) {}
  
  bool operator== (const CIString& b) const {
      return ci_compare(str_.c_str(), b.str_.c_str()) == 0;
  }
 
  std::weak_ordering operator<=>(const CIString& b) const {
       return ci_compare(str_.c_str(), b.str_.c_str()) <=> 0;//strong_ordering返回為weak_ordering類型,實(shí)際上發(fā)生了類型轉(zhuǎn)換
  }
private:
  std::string str_;
};

int main(int argc,char* argv[])
{
    CIString s1( "hello" ), s2( "world" );
    bool r = true;
    r = s1 == s2;
    std::cout<<std::boolalpha<<r<<std::endl;
    r = s1 != s2;
    std::cout<<std::boolalpha<<r<<std::endl;
    r = s1 > s2;
    std::cout<<std::boolalpha<<r<<std::endl;
    r = s1 >= s2;
    std::cout<<std::boolalpha<<r<<std::endl;
    r = s1 < s2;
    std::cout<<std::boolalpha<<r<<std::endl;
    r = s1 <= s2;
    std::cout<<std::boolalpha<<r<<std::endl;
    return 0;
}

false
true
false
false
true
true

五、兼容他舊代碼

現(xiàn)在C++20標(biāo)準(zhǔn)已經(jīng)推薦使用<=>和==運(yùn)算符自動(dòng)生成其他比較運(yùn)算符函數(shù),而使用<、==以及std::rel_ops生成其他比較運(yùn)算符函數(shù)則會(huì)因?yàn)閟td::rel_ops已經(jīng)不被推薦使用而被編譯器警告。那么對(duì)于老代碼,我們是否需要去實(shí)現(xiàn)一套<=>和==運(yùn)算符函數(shù)呢?其實(shí)大可不必,C++委員會(huì)在裁決這項(xiàng)修改的時(shí)候已經(jīng)考慮到老代碼的維護(hù)成本,所以做了兼容性處理,即在用戶自定義類型中,實(shí)現(xiàn)了<、==運(yùn)算符函數(shù)的數(shù)據(jù)成員類型,在該類型的三向比較中將自動(dòng)生成合適的比較代碼。比如:

#include <iostream>
 
struct Legacy {
  int n=0;
  bool operator==(const Legacy& rhs) const
  {
       return n == rhs.n;
  }
  bool operator<(const Legacy& rhs) const
  {
       return n < rhs.n;
  }
};

struct TreeWay {
  Legacy m;
  std::strong_ordering operator<=>(const TreeWay &) const = default;
};

int main(int argc,char* argv[])
{
    TreeWay t1, t2;
    bool r = t1 < t2;
    std::cout<<std::boolalpha<<r<<std::endl;
    return 0;
}

在上面的代碼中,結(jié)構(gòu)體TreeWay的三向比較操作會(huì)調(diào)用結(jié)構(gòu)體Legacy中的<和==運(yùn)算符來完成,其代碼類似于:

struct TreeWay {
  Legacy m;
  std::strong_ordering operator<=>(const TreeWay& rhs) const {
       if (m < rhs.m) return std::strong_ordering::less;
       if (m == rhs.m) return std::strong_ordering::equal;
       return std::strong_ordering::greater;
  }
};

需要注意的是,這里operator<=>必須顯式聲明返回類型為std::strong_ ordering,使用auto是無法通過編譯的。

到此這篇關(guān)于c++20引入的三路比較操作符<=>的文章就介紹到這了,更多相關(guān)c++20三路比較操作符內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C++通過文件指針獲取文件大小的方法實(shí)現(xiàn)

    C++通過文件指針獲取文件大小的方法實(shí)現(xiàn)

    本文主要介紹了C++通過文件指針獲取文件大小的方法實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-01-01
  • C++深入探究不同的繼承體系

    C++深入探究不同的繼承體系

    繼承是C++面向?qū)ο缶幊讨械囊婚T。繼承是子類繼承父類的特征和行為,或者是繼承父類得方法,使的子類具有父類得的特性和行為。重寫是子類對(duì)父類的允許訪問的方法實(shí)行的過程進(jìn)行重新編寫,返回值和形參都不能改變。就是對(duì)原本的父類進(jìn)行重新編寫,但是外部接口不能被重寫
    2022-05-05
  • 詳解C語言中rand函數(shù)的使用

    詳解C語言中rand函數(shù)的使用

    在編程時(shí)我們有時(shí)總希望自己產(chǎn)生一個(gè)隨機(jī)數(shù)字,以供使用,那么下面介紹rand函數(shù)的使用,有需要的可以參考學(xué)習(xí)。
    2016-08-08
  • C語言MFC基礎(chǔ)之計(jì)算器詳解

    C語言MFC基礎(chǔ)之計(jì)算器詳解

    這篇文章主要為大家介紹了MFC實(shí)現(xiàn)簡(jiǎn)單的計(jì)算器,文中介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2021-08-08
  • OpenCV實(shí)現(xiàn)鼠標(biāo)在圖像上框選單目標(biāo)和多目標(biāo)

    OpenCV實(shí)現(xiàn)鼠標(biāo)在圖像上框選單目標(biāo)和多目標(biāo)

    這篇文章主要為大家詳細(xì)介紹了OpenCV實(shí)現(xiàn)鼠標(biāo)在圖像上框選單目標(biāo)和多目標(biāo),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-08-08
  • 使用C語言編寫圣誕表白程序

    使用C語言編寫圣誕表白程序

    圣誕節(jié)快到了,讓我們用C語言制作一個(gè)圣誕表白程序吧,下面通過本文學(xué)習(xí)下實(shí)現(xiàn)代碼
    2016-12-12
  • 用C語言如何打印一個(gè)等腰三角形

    用C語言如何打印一個(gè)等腰三角形

    這篇文章主要介紹了用C語言如何打印一個(gè)等腰三角形,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-11-11
  • C語言中atoi函數(shù)模擬實(shí)現(xiàn)詳析

    C語言中atoi函數(shù)模擬實(shí)現(xiàn)詳析

    atoi函數(shù)功能是將數(shù)字字符串轉(zhuǎn)換為整數(shù),比如數(shù)字字符串"12345"被atoi轉(zhuǎn)換為12345,數(shù)字字符串"-12345"被轉(zhuǎn)換為-12345,下面這篇文章主要給大家介紹了關(guān)于C語言中atoi函數(shù)模擬實(shí)現(xiàn)的相關(guān)資料,需要的朋友可以參考下
    2022-10-10
  • 帶你了解C++的IO流

    帶你了解C++的IO流

    這篇文章主要介紹了C++ IO流的相關(guān)資料,幫助大家更好的理解和學(xué)習(xí)c++,感興趣的朋友可以了解下,希望能夠給你帶來幫助
    2021-09-09
  • C++類中如何使用定義的類型別名

    C++類中如何使用定義的類型別名

    這篇文章主要介紹了C++類中如何使用定義的類型別名,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-11-11

最新評(píng)論