Toán tử <=> trong C ++ là gì?


215

Trong khi tôi đang cố gắng tìm hiểu về các toán tử C ++ , tôi tình cờ thấy một toán tử so sánh lạ trên cppreference.com , * trong một bảng trông như thế này:

nhập mô tả hình ảnh ở đây

"Chà, nếu đây là những toán tử phổ biến trong C ++, tôi nên học chúng tốt hơn", tôi nghĩ. Nhưng tất cả những nỗ lực của tôi để làm sáng tỏ bí ẩn này đã không thành công. Ngay cả ở đây, trên Stack Overflow tôi không gặp may mắn trong tìm kiếm của mình.

Có mối liên hệ nào giữa <=>C ++ không?

Và nếu có, toán tử này làm gì chính xác?

* Trong khi đó, cppreference.com đã cập nhật trang đó và hiện chứa thông tin về <=>nhà điều hành.


82
@haccks: Ồ làm ơn, chúng tôi đã có rất nhiều câu hỏi về những thứ thậm chí không được bình chọn theo tiêu chuẩn. Chúng tôi có một thẻ C ++ 20 vì một lý do. Loại công cụ này rất nhiều là về chủ đề.
Nicol Bolas

1
@ cubuspl42 bar< foo::operator<=>là một ví dụ về cách nó có thể giống như <--toán tử.
Yakk - Adam Nevraumont

8
@haccks: Đúng vậy. Giống như C ++ 11 là một thẻ về trình biên dịch triển khai C ++ 11. Và C ++ 14 là một thẻ về trình biên dịch triển khai C ++ 14. Và C ++ 17 là về trình biên dịch triển khai C ++ 17. Không, C ++ 20 là thẻ cho những thứ về C ++ 20. Và vì câu hỏi này là về C ++ 20, nên nó có. Các thẻ wiki đã sai, không phải chính thẻ.
Nicol Bolas

Câu trả lời:


180

Đây được gọi là toán tử so sánh ba chiều .

Theo đề xuất giấy P0515 :

Có một toán tử so sánh ba chiều mới , <=>. Biểu thức a <=> btrả về một đối tượng so sánh <0if a < b, so sánh >0if a > bvà so sánh ==0if abbằng / tương đương.

Để viết tất cả các so sánh cho loại của bạn, chỉ cần viết operator<=>trả về loại danh mục phù hợp:

  • Quay trở lại một _ordering nếu loại của bạn hỗ trợ một cách tự nhiên <, và chúng tôi sẽ có hiệu quả tạo <, >, <=, >=, ==, và !=; mặt khác trả về một _equality và chúng tôi sẽ tạo hiệu quả ==! = .

  • Trả về mạnh nếu cho loại của bạn a == bngụ ý f(a) == f(b)(khả năng thay thế, trong đó f chỉ đọc trạng thái so sánh có thể truy cập bằng giao diện constprivate const), nếu không thì trả về yếu.

Các cppreference nói:

Các biểu thức toán tử so sánh ba chiều có dạng

lhs <=> rhs   (1)  

Biểu thức trả về một đối tượng

  • so sánh <0nếulhs < rhs
  • so sánh >0nếulhs > rhs
  • và so sánh ==0nếu lhsrhsbằng / tương đương.

93
Đối với những người bối rối (như tôi) về "so sánh <0", "so sánh >0" và "so sánh ==0" nghĩa là gì, họ có nghĩa là <=>trả về giá trị âm, dương hoặc bằng 0, tùy thuộc vào các đối số. Rất thích strncmpmemcmp.
Bắp ngô

1
@Dai mặc dù cả hai 'a' < 'a''c' < 'a'đều sai, 'a' < 'a''a' < 'c'không. Theo thứ tự mạnh mẽ sau đây là đúng: a != ba < b || b < a
Revolver_Ocelot

1
@Revolver_Ocelot Ah, vì vậy nó có thể được định nghĩa / tạo thành operator==(T x, T y) { return !(x < y) && !(y < x); }operator!=(T x, T y) { return (x < y) || (y < x); }- ah-ha! Tất nhiên điều này kém hiệu quả hơn so với sự thật ==vì nó gọi phép so sánh hai lần, nhưng vẫn gọn gàng.
Đại

3
"Trở lại mạnh mẽ" và "trở lại yếu đuối" nghĩa là gì?
lucidbrot

2
@hkBattousai có nghĩa là đối tượng trả về, khi so sánh < 0đánh giá là đúng. Đó là, nếu a < bsau đó (a <=> b) < 0luôn luôn đúng.
rmobis

116

Vào ngày 2017-11-11 , ủy ban ISO C ++ đã thông qua đề xuất của Herb Sutter cho toán tử so sánh ba chiều <=> "tàu vũ trụ" là một trong những tính năng mới được thêm vào C ++ 20 . Trong bài báo có tiêu đề So sánh nhất quán Sutter, Maurer và Brown trình bày các khái niệm của thiết kế mới. Để biết tổng quan về đề xuất, đây là một đoạn trích từ bài viết:

Biểu thức a <=> b trả về một đối tượng so sánh <0 nếu a <b , so sánh > 0 nếu a> b và so sánh == 0 nếu a và b bằng / tương đương.

Trường hợp phổ biến: Để viết tất cả các so sánh cho loại X của bạn với loại Y , với ngữ nghĩa thành viên, chỉ cần viết:

auto X::operator<=>(const Y&) =default;

Các trường hợp nâng cao: Để viết tất cả các so sánh cho loại X của bạn với loại Y , chỉ cần viết toán tử <=> lấy Y , có thể sử dụng = mặc định để lấy ngữ nghĩa thành viên nếu muốn và trả về loại danh mục phù hợp:

  • Trả về một _ordering nếu loại của bạn hỗ trợ một cách tự nhiên < và chúng tôi sẽ tạo đối xứng < , > , <= , > = , == , và ! = ; mặt khác trả về một _equality và chúng ta sẽ tạo đối xứng một cách hiệu quả ==! = .
  • Trả về strong_ nếu cho loại của bạn a == b ngụ ý f (a) == f (b) (khả năng thay thế, trong đó f chỉ đọc trạng thái so sánh có thể truy cập bằng cách sử dụng các thành viên const công khai ), nếu không thì trả về yếu_ .

Danh mục so sánh

Năm loại so sánh được định nghĩa là std::các loại, mỗi loại có các giá trị được xác định trước:

+--------------------------------------------------------------------+
|                  |          Numeric  values          | Non-numeric |
|     Category     +-----------------------------------+             |
|                  | -1   | 0          | +1            |   values    |
+------------------+------+------------+---------------+-------------+
| strong_ordering  | less | equal      | greater       |             |
| weak_ordering    | less | equivalent | greater       |             |
| partial_ordering | less | equivalent | greater       | unordered   |
| strong_equality  |      | equal      | nonequal      |             |
| weak_equality    |      | equivalent | nonequivalent |             |
+------------------+------+------------+---------------+-------------+

Chuyển đổi ngầm định giữa các loại này được xác định như sau:

  • strong_orderingvới các giá trị { less, equal, greater} ngầm chuyển đổi thành:
    • weak_orderingvới các giá trị { less, equivalent, greater}
    • partial_orderingvới các giá trị { less, equivalent, greater}
    • strong_equalityvới các giá trị { unequal, equal, unequal}
    • weak_equalityvới các giá trị { nonequivalent, equivalent, nonequivalent}
  • weak_orderingvới các giá trị { less, equivalent, greater} ngầm chuyển đổi thành:
    • partial_orderingvới các giá trị { less, equivalent, greater}
    • weak_equalityvới các giá trị { nonequivalent, equivalent, nonequivalent}
  • partial_orderingvới các giá trị { less, equivalent, greater, unordered} ngầm chuyển đổi thành:
    • weak_equalityvới các giá trị { nonequivalent, equivalent, nonequivalent, nonequivalent}
  • strong_equalityvới các giá trị { equal, unequal} hoàn toàn chuyển đổi thành:
    • weak_equalityvới các giá trị { equivalent, nonequivalent}

So sánh ba chiều

<=>thông báo được giới thiệu. Chuỗi ký tự <=>mã hóa <= >, trong mã nguồn cũ. Ví dụ, X<&Y::operator<=>cần thêm một khoảng trắng để giữ lại ý nghĩa của nó.

Toán tử quá tải <=>là một hàm so sánh ba chiều và có độ ưu tiên cao hơn <và thấp hơn <<. Nó trả về một loại có thể được so sánh với nghĩa đen 0nhưng các loại trả về khác được cho phép như để hỗ trợ các mẫu biểu thức. Tất cả các <=>toán tử được xác định trong ngôn ngữ và trong thư viện chuẩn trả về một trong 5 std::loại danh mục so sánh đã nói ở trên .

Đối với các loại ngôn ngữ, các <=>so sánh cùng loại tích hợp sau được cung cấp. Tất cả đều là constexpr , trừ khi có ghi chú khác. Những so sánh này không thể được gọi một cách không đồng nhất bằng cách sử dụng các chương trình khuyến mãi / chuyển đổi vô hướng.

  • Đối với bool, tích phân và các loại con trỏ, <=>trả về strong_ordering.
  • Đối với các loại con trỏ, các trình độ cv khác nhau và các chuyển đổi xuất phát từ cơ sở được phép gọi một tích hợp đồng nhất <=>và có tích hợp không đồng nhất operator<=>(T*, nullptr_t). Chỉ so sánh các con trỏ với cùng một đối tượng / phân bổ là các biểu thức không đổi.
  • Đối với các loại dấu phẩy động cơ bản, <=>trả về partial_orderingvà có thể được gọi một cách không đồng nhất bằng cách mở rộng các đối số thành một loại dấu phẩy động lớn hơn.
  • Đối với bảng liệt kê, <=>trả về giống như kiểu cơ bản của kiểu liệt kê <=>.
  • Cho nullptr_t, <=>trả lại strong_orderingvà luôn luôn mang lại equal.
  • Đối với các mảng có thể sao chép, T[N] <=> T[N]trả về cùng loại với T's <=>và thực hiện so sánh theo nguyên tố từ điển. Không có <=>cho các mảng khác.
  • voidkhông có <=>.

Để hiểu rõ hơn về hoạt động bên trong của nhà điều hành này, xin vui lòng đọc bài báo gốc . Đây chỉ là những gì tôi đã tìm ra bằng cách sử dụng các công cụ tìm kiếm.


1
Như thể cpp chưa đủ phức tạp. Tại sao không chỉ đơn giản là viết một phương pháp so sánh ...
Leandro

6
@Leandro Toán tử tàu vũ trụ phương pháp so sánh đó. Ngoài ra, nó chỉ hoạt động và ghi (hoặc xóa) sáu toán tử so sánh khác. Tôi sẽ lấy một hàm toán tử so sánh được viết trên sáu mẫu riêng lẻ.
ẩn danh

Lưu ý rằng các _equalityloại đã chết: hóa ra nó <=>chơi tốt với bốn toán tử quan hệ nhưng không tốt với hai toán tử đẳng thức (mặc dù có một số cú pháp cú pháp mãnh liệt để hỗ trợ cho trường hợp chung mà bạn muốn tất cả chúng).
Davis Herring

12

Câu trả lời này đã trở nên không liên quan vì trang web được tham chiếu đã thay đổi

Các trang web mà bạn đang tham chiếu đã bị hỏng. Nó đã được chỉnh sửa rất nhiều vào ngày hôm đó và các phần khác nhau không đồng bộ. Trạng thái khi tôi đang xem nó là:

Ở đầu trang, nó liệt kê các toán tử so sánh hiện có (trong C ++ 14). Không có <=>ở đó.

Ở dưới cùng của trang, họ nên liệt kê các toán tử tương tự, nhưng họ đã ủng hộ và thêm đề xuất trong tương lai này.

gccchưa biết về <=>(và với -std=c++14, sẽ không bao giờ), vì vậy nó nghĩ bạn có ý gì a <= > b. Điều này là giải thích thông báo lỗi.

Nếu bạn thử điều tương tự năm năm kể từ bây giờ, bạn có thể sẽ nhận được thông báo lỗi tốt hơn, đại loại như <=> not part of C++14.


1
Trang web OP liên kết đến là chính xác, như là trang riêng mà bạn liên kết đến. Nó đủ điều kiện cho người <=>vận hành với nhãn (kể từ C ++ 20), cho bạn biết phiên bản nào của tiêu chuẩn để mong đợi. Ghi nhãn tiêu chuẩn là một quy ước mà cppreference.com tuân theo. Tất nhiên bạn không có trình biên dịch quay lại trong cỗ máy thời gian để hỗ trợ nó cho bạn, nhưng cpprefernce cho bạn biết (chính xác) những gì mong đợi.
Spencer

Phải, nhưng ... Không phải là một câu trả lời. Bạn đang bình luận ... hoặc một cái gì đó.
qlp

2
Tôi dự định liên kết đến cùng một trang web như câu hỏi, nhưng đã bỏ lỡ. Tôi nghĩ rằng tôi đã trả lời các phần của câu hỏi khác. Tôi bỏ qua câu hỏi in đậm chính vì người khác đã trả lời rằng.
Stig Hemmer
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.