首页 > 编程知识 正文

C 20三路比较运算符,三目运算符的运算规则

时间:2023-05-03 11:47:26 阅读:248490 作者:1181

C++20的三路比较运算符 operator<=> 01 默认比较01.01 默认比较01.02 定制比较强序弱序偏序 02 C++20的关系运算符与比较接口03 参考
三路比较运算符 <=> 通常被称为宇宙飞船运算符(spaceship operator)。可以执行字典序比较,它按照基类从左到右的顺序,并按字段声明顺序对非静态成员进行比较。
在类ClassName中预置 <=> 运算符 auto operator<=>(const ClassName&) const = default; 后,编译器会生成全部共六个比较运算符,如 ==、!=、<、<=、> 和 >= 。

01 默认比较 01.01 默认比较

默认比较1提供一种方式,以要求编译器为某个类生成相一致的关系运算符。

简言之,定义了 operator<=> 的类自动获得由编译器生成的运算符 ==、!=、<、<=、> 和 >=。类可以将 operator<=> 定义为预置的,这种情况下编译器亦将为该运算符生成代码。

class Point { int x; int y;public: Point(int a, int b) :x(a), y(b) {} auto operator<=>(const Point&) const = default; // 预置 operator<=> // 因为预置 operator<=>,现在能用 ==、!=、<、<=、> 和 >= 比较 Point // ……非比较函数……};void test_compare01() { // 编译器生成全部四个关系运算符 Point pt1{ 1, 2 }, pt2{1, 3}; std::set<Point> s; // OK s.insert(pt1); // OK s.insert(pt2); if (pt1 <= pt2) { // OK,只调用一次 <=> std::cout << "pt1 <= pt2n"; } else { std::cout << "! (pt1 <= pt2)n"; }} 01.02 定制比较

如果预置的语义不适合,例如在必须不按各成员的顺序进行比较,或必须用某种不同于它们的自然比较操作的比较,这种情况下程序员可以编写 operator<=> 并令编译器生成适合的关系运算符。生成的关系运算符种类取决于用户定义 operator<=> 的返回类型。

有三种可用的返回类型:

返回类型运算符等价的值……不可比较的值……(强序)std::strong_ordering== != < > <= >=不可区分不允许存在(弱序)std::weak_ordering== != < > <= >=可区分不允许存在(偏序)std::partial_ordering== != < > <= >=可区分允许存在强序

一个返回 std::strong_ordering 的定制 operator<=> 的例子是,对类的每个成员进行比较的运算符,但与默认的顺序有所不同(此处为姓优先)。

注意:返回 std::strong_ordering 的运算符应该对所有成员都进行比较,因为遗漏了任何成员都将会损害可替换性:二个比较相等的值可能变得可以区分。

class Base {public: auto operator<=>(const Base&) const = default;};std::strong_ordering operator <=>(const std::string& a, const std::string& b) { int cmp = a.compare(b); if (cmp < 0) return std::strong_ordering::less; else if (cmp > 0) return std::strong_ordering::greater; else return std::strong_ordering::equivalent;}class TotallyOrdered : Base { std::string tax_id; std::string first_name; std::string last_name;public: TotallyOrdered(const std::string& id, const std::string& first, const std::string& last) :tax_id(id), first_name(first), last_name(last) {} // 定制 operator<=>,因为我们想先比较姓 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; } // ……非比较函数……};void test_compare02() { // 编译器生成全部四个关系运算符 TotallyOrdered to1{ "1", "first1", "last1" }, to2{ "2", "first2", "last2" }; std::set<TotallyOrdered> s; // ok s.insert(to1); // ok s.insert(to2); if (to1 <= to2) { // ok,调用一次 <=> std::cout << "to1 <= to2n"; } else { std::cout << "!(to1 <= to2)n"; }} 弱序

一个返回 std::weak_ordering 的定制 operator<=> 的例子是,以大小写无关方式比较类的字符串成员的运算符:这不同于默认比较(故要求定制运算符),并且在这种比较下有可能对比较相等的两个字符串加以区分。

注意,此示例演示了异质 operator<=> 所具有的效果:它在两个方向都生成了异质的比较。

class CaseInsensitiveString { std::string s; std::weak_ordering case_insensitive_compare( const char* a, const char* b) const { int cmp = _stricmp(a, b); if (cmp < 0) return std::weak_ordering::less; else if (cmp > 0) return std::weak_ordering::greater; else return std::weak_ordering::equivalent; }public: CaseInsensitiveString(const std::string& str) : s(str) {} std::weak_ordering operator<=>(const CaseInsensitiveString& b) const { return case_insensitive_compare(s.c_str(), b.s.c_str()); } std::weak_ordering operator<=>(const char* b) const { return case_insensitive_compare(s.c_str(), b); } // ……非比较函数……};void test_compare03() { // 编译器生成全部四个关系运算符 CaseInsensitiveString cis1{ "XYzza" }, cis2{ "xyzza" }; std::set<CaseInsensitiveString> s; // ok s.insert(cis1); // ok s.insert(cis2); if (cis1 <= cis2) {// ok,进行一次比较运算 std::cout << "cis1 <= cis2n"; } // 编译器亦生成全部八个异相关系运算符 if (cis1 <= "xyzzy") {// ok,进行一次比较运算 std::cout << "cis1 <= "xyzzy"n"; } if ("xyzzy" >= cis1) {// ok,等同的语义 std::cout << ""zyzzy" >= cis1n"; }} 偏序

偏序是允许存在不可比较(无序)值的排序,例如浮点排序中的 NaN 值,或这个例子中的无关人员:

class PersonInFamilyTree {private: int parent_family_level_id = -1; int self_family_level_id = -1; bool is_the_same_person_as(const PersonInFamilyTree& rhs) const { return (self_family_level_id >= 0 && (self_family_level_id == rhs.self_family_level_id)); } bool is_transitive_child_of(const PersonInFamilyTree& rhs) const { return (rhs.self_family_level_id >= 0 && (parent_family_level_id == rhs.self_family_level_id)); }public: PersonInFamilyTree(int parent, int self) : parent_family_level_id(parent), self_family_level_id(self) {} std::partial_ordering operator<=>(const PersonInFamilyTree& that) const { if (this->is_the_same_person_as(that)) return std::partial_ordering::equivalent; if (this->is_transitive_child_of(that)) return std::partial_ordering::less; if (that.is_transitive_child_of(*this)) return std::partial_ordering::greater; return std::partial_ordering::unordered; } // ……非比较函数……};void test_compare04() { // 编译器生成全部四个关系运算符 PersonInFamilyTree per1{ 0, 1 }, per2{ 1, 10 }; if (per1 < per2) { std::cout << "ok, per2 是 per1 的祖先n"; } else if (per1 > per2) { std::cout << "ok, per1 是 per2 的祖先n"; } else if (std::is_eq(per1 <=> per2)) { std::cout << "ok, per1 即是 per2n"; } else { std::cout << "per1 与 per2 无关n"; } if (per1 <= per2) { std::cout << "ok, per2 是 per1 或 per1 的祖先n"; } if (per1 >= per2) { std::cout << "ok, per1 是 per2 或 per2 的祖先n"; } if (std::is_neq(per1 <=> per2)) { std::cout << "ok, per1 不是 per2n"; }} 02 C++20的关系运算符与比较接口

关系运算符与比较2。定义于头文件 <compare>。

方法说明three_way_comparable
three_way_comparable_with指定运算符 <=> 在给定类型上产生一致的结果partial_ordering三路比较的结果类型,支持所有 6 种运算符,不可替换,并允许不可比较的值weak_ordering三路比较的结果类型,支持所有 6 种运算符且不可替换strong_ordering三路比较的结果类型,支持所有 6 种运算符且可替换is_eq
is_neq
is_lt
is_lteq
is_gt
is_gteq具名比较函数compare_three_way实现 x <=> y 的函数对象compare_three_way_result获得三路比较运算符 <=> 在给定类型上的结果common_comparison_category给定的全部类型都能转换到的最强比较类别strong_order进行三路比较并产生 std::strong_ordering 类型结果weak_order进行三路比较并产生 std::weak_ordering 类型结果partial_order进行三路比较并产生 std::partial_ordering 类型结果compare_strong_order_fallback进行三路比较并产生 std::strong_ordering 类型的结果,即使 operator<=> 不可用compare_weak_order_fallback进行三路比较并产生 std::weak_ordering 类型的结果,即使 operator<=> 不可用compare_partial_order_fallback进行三路比较并产生 std::partial_ordering 类型的结果,即使 operator<=> 不可用03 参考

A: 微软博客Simplify Your Code With Rocket Science: C++20’s Spaceship Operator
B: 比较运算符(https://zh.cppreference.com/w/cpp/language/operator_comparison)
C: operator<=> for C++20入门篇
D: 文中代码https://github.com/5455945/cpp_demo/blob/master/C%2B%2B20/compare/compare.cpp
E: Visual Studio 2019 版本 16.4 的符合性改进


默认比较(https://zh.cppreference.com/w/cpp/language/default_comparisons) ↩︎

关系运算符与比较(https://zh.cppreference.com/w/cpp/utility) ↩︎

win7电脑文件夹如何加密运行JSONEncode时是否可以排除已经为JSON的字段?

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。