赞
踩
三向比较(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<=>的内容来达成的~
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。