三向比較運算符
當我們在寫自己的 struct or class 時,有時候要去該物件的比較, 也就是 <, <=, ==, !=, >=, > 這些 operator。 但寫過的人就知道,上述 6 個 operator 都要去寫非常麻煩。 而且還很容易錯誤。
C++20 引入了三向比較運算符(spaceship operator, <=>
),它是一個新的比較工具, 可以統一和簡化比較操作。
三向比較運算符 <=>
的主要功能是: 統一比較運算符:只需要定義一個運算符,即可自動生成所有的比較運算符(<, <=, ==, !=, >=, >)。
code
下面的 code 我們定義一個三維空間中的 Point, 所以會有 x,y,z 的座標。 現在我們來定義這幾個 Point 比大小(先不管物理意義啦)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#include <iostream>
#include <compare>
class Point {
public:
Point(int x, int y, int z) : x(x), y(y), z(z) {}
// 使用 default 自動生成
auto operator<=>(const Point& other) const = default;
// 友元函数聲明
friend std::ostream& operator<<(std::ostream& os, const Point& point);
private:
int x, y, z;
};
// 友元函数定義
std::ostream& operator<<(std::ostream& os, const Point& point) {
os << "Point(" << point.x << ", " << point.y << ", " << point.z << ")";
return os;
}
auto printHelper(bool result)
{
if (result)
return "True";
else
return "False";
}
int main() {
Point p1{ 2, 1, 3 };
Point p2{ 1, 1, 4 };
Point p3{ 3, 3, 4 };
std::cout << p1 << std::endl;
std::cout << p2 << std::endl;
std::cout << p3 << std::endl;
std::cout << "------------" << std::endl;
// 比較 p1 和 p2
std::cout << "(p1 == p2): " << printHelper(p1 == p2) << std::endl;
std::cout << "(p1 < p2): " << printHelper(p1 < p2) << std::endl;
std::cout << "(p1 > p2): " << printHelper(p1 > p2) << std::endl;
// 比較 p1 和 p3
std::cout << "(p1 == p3): " << printHelper(p1 == p3) << std::endl;
std::cout << "(p1 < p3): " << printHelper(p1 < p3) << std::endl;
std::cout << "(p1 > p3): " << printHelper(p1 > p3) << std::endl;
return 0;
}
當你使用 auto operator<=>(const Point& other) const = default
時, 編譯器自動為你生成三向比較運算符, 並按照成員變量的順序進行比較。 這樣做的結果與手動實現的比較邏輯是一致的。
編譯器生成的比較邏輯如下:
- 按成員變量聲明的順序依次進行比較。不論成員變量是
public
、protected
還是private
。編譯器會考慮所有成員變量來生成比較邏輯。 - 每個成員變量都使用
<=>
進行比較。 - 如果某個成員的比較結果不是 equal,則返回該結果。
- 如果所有成員都相等,則返回 equal。
手動定義三向比較運算符
當你想要自己定義三向比較運算符時,譬如你覺得比較順序要使用 z -> y -> x
1
2
3
4
5
6
7
8
9
10
11
12
// 手動定義三向比較運算符
auto operator<=>(const Point& other) const {
if (auto cmp = z <=> other.z; cmp != 0) {
return cmp;
}
if (auto cmp = y <=> other.y; cmp != 0) {
return cmp;
}
return x <=> other.x;
}
這時候 complier 報錯了。
這個錯誤是因為當你定義了三向比較運算符 <=>
時,編譯器期望你也提供等於運算符 == 的定義。雖然 <=> 可以生成 <、<=、> 和 >=,但它不會自動生成 == 和 !=。
你需要手動定義 == 運算符。
1
2
3
4
// 手動定義等於運算符
bool operator==(const Point& other) const {
return x == other.x && y == other.y && z == other.z;
}
比較順序 z->y->x
code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
#include <iostream>
#include <compare>
class Point {
public:
Point(int x, int y, int z) : x(x), y(y), z(z) {}
// 手動定義三向比較運算符
auto operator<=>(const Point& other) const {
if (auto cmp = z <=> other.z; cmp != 0) {
return cmp;
}
if (auto cmp = y <=> other.y; cmp != 0) {
return cmp;
}
return x <=> other.x;
}
// 手動定義等於運算符
bool operator==(const Point& other) const {
return x == other.x && y == other.y && z == other.z;
}
// 友元函数聲明
friend std::ostream& operator<<(std::ostream& os, const Point& point);
private:
int x, y, z;
};
// 友元函数定義
std::ostream& operator<<(std::ostream& os, const Point& point) {
os << "Point(" << point.x << ", " << point.y << ", " << point.z << ")";
return os;
}
auto printHelper(bool result)
{
if (result)
return "True";
else
return "False";
}
int main() {
Point p1{ 2, 1, 3 };
Point p2{ 1, 1, 4 };
Point p3{ 3, 3, 4 };
std::cout << p1 << std::endl;
std::cout << p2 << std::endl;
std::cout << p3 << std::endl;
std::cout << "------------" << std::endl;
// 比較 p1 和 p2
std::cout << "(p1 == p2): " << printHelper(p1 == p2) << std::endl;
std::cout << "(p1 < p2): " << printHelper(p1 < p2) << std::endl;
std::cout << "(p1 > p2): " << printHelper(p1 > p2) << std::endl;
// 比較 p1 和 p3
std::cout << "(p1 == p3): " << printHelper(p1 == p3) << std::endl;
std::cout << "(p1 < p3): " << printHelper(p1 < p3) << std::endl;
std::cout << "(p1 > p3): " << printHelper(p1 > p3) << std::endl;
return 0;
}
使用時機
需要比較對象:當需要對對象進行排序或比較時,例如在排序演算法、二叉搜索樹、優先隊列等數據結構中。
需要多個比較運算符:當類需要定義多個比較運算符時(例如 <, <=, >, >=, ==, !=),使用
<=>
可以簡化這些運算符的定義。實現自定義排序邏輯:當類需要自定義排序邏輯時,可以通過自定義
<=>
運算符來實現。
以上。呼