Toán tử đẳng thức không được xác định cho việc triển khai toán tử tàu vũ trụ tùy chỉnh trong C ++ 20


51

Tôi đang gặp phải một hành vi kỳ lạ với toán tử tàu vũ trụ mới <=>trong C ++ 20. Tôi đang sử dụng trình biên dịch Visual Studio 2019 với /std:c++latest.

Mã này biên dịch tốt, như mong đợi:

#include <compare>

struct X
{
    int Dummy = 0;
    auto operator<=>(const X&) const = default; // Default implementation
};

int main()
{
    X a, b;

    a == b; // OK!

    return 0;
}

Tuy nhiên, nếu tôi thay đổi X thành này:

struct X
{
    int Dummy = 0;
    auto operator<=>(const X& other) const
    {
        return Dummy <=> other.Dummy;
    }
};

Tôi nhận được lỗi trình biên dịch sau:

error C2676: binary '==': 'X' does not define this operator or a conversion to a type acceptable to the predefined operator

Tôi cũng đã thử điều này trên clang và tôi cũng có hành vi tương tự.

Tôi sẽ đánh giá cao một số giải thích về lý do tại sao việc triển khai mặc định tạo ra operator==chính xác, nhưng tùy chỉnh thì không.

Câu trả lời:


50

Đây là do thiết kế.

[class.compare.default] (nhấn mạnh của tôi)

3 Nếu định nghĩa lớp không khai báo rõ ràng == hàm toán tử, nhưng khai báo hàm toán tử so sánh ba chiều mặc định , ==hàm toán tử được khai báo ngầm với cùng quyền truy cập như hàm toán tử so sánh ba chiều. ==Toán tử được khai báo ngầm cho lớp X là một thành viên nội tuyến và được định nghĩa là mặc định trong định nghĩa của X.

Chỉ có một mặc định <=>cho phép một tổng hợp ==tồn tại. Lý do là các lớp như std::vectorkhông thể sử dụng mặc định <=>. Ngoài ra, sử dụng <=>for ==không phải là cách hiệu quả nhất để so sánh các vectơ. <=>phải đưa ra thứ tự chính xác, trong khi ==có thể bảo lãnh sớm bằng cách so sánh kích thước trước.

Nếu một lớp làm một cái gì đó đặc biệt trong so sánh ba chiều của nó, nó có thể sẽ cần phải làm một cái gì đó đặc biệt trong nó ==. Do đó, thay vì tạo một mặc định không hợp lý, ngôn ngữ sẽ để nó cho lập trình viên.


4
Nó chắc chắn hợp lý, trừ khi tàu vũ trụ là lỗi. Có khả năng rất kém hiệu quả mặc dù ...
Ded repeatator

1
@Ded repeatator - Sự nhạy cảm là chủ quan. Một số người sẽ nói rằng việc thực hiện không hiệu quả âm thầm là không hợp lý.
Người kể chuyện - Unslander Monica

45

Trong quá trình tiêu chuẩn hóa tính năng này, người ta đã quyết định rằng sự bình đẳng và trật tự cần được tách biệt một cách hợp lý. Như vậy, việc sử dụng kiểm tra đẳng thức ( ==!=) sẽ không bao giờ gọi operator<=>. Tuy nhiên, nó vẫn được xem là hữu ích để có thể mặc định cả hai chỉ với một khai báo. Vì vậy, nếu bạn mặc định operator<=>, bạn đã quyết định rằng bạn cũng có nghĩa là mặc định operator==(trừ khi bạn xác định nó sau hoặc đã xác định trước đó).

Về lý do tại sao quyết định này được đưa ra , lý luận cơ bản diễn ra như thế này. Xem xétstd::string . Thứ tự của hai chuỗi là từ điển; mỗi ký tự có giá trị nguyên so với từng ký tự trong chuỗi khác. Sự bất bình đẳng đầu tiên dẫn đến kết quả của việc đặt hàng.

Tuy nhiên, kiểm tra đẳng thức của chuỗi có ngắn mạch. Nếu hai chuỗi không có độ dài bằng nhau, thì không có điểm nào trong việc so sánh thông minh nhân vật cả; họ không bằng nhau. Vì vậy, nếu ai đó đang thực hiện kiểm tra bình đẳng, bạn không muốn thực hiện dưới dạng dài nếu bạn có thể làm ngắn mạch.

Nó chỉ ra rằng nhiều loại cần một thứ tự do người dùng xác định cũng sẽ cung cấp một số cơ chế ngắn mạch để kiểm tra công bằng. Để ngăn mọi người chỉ thực hiện operator<=>và vứt bỏ hiệu suất tiềm năng, chúng tôi buộc mọi người phải làm cả hai một cách hiệu quả.


5
Đây là một lời giải thích tốt hơn nhiều so với câu trả lời được chấp nhận
bản ghi nhớ

17

Các câu trả lời khác giải thích thực sự tốt tại sao ngôn ngữ là như thế này. Tôi chỉ muốn thêm rằng trong trường hợp không rõ ràng, tất nhiên có thể có một người dùng được cung cấp operator<=>với một mặc định operator==. Bạn chỉ cần viết rõ ràng mặc định operator==:

struct X
{
    int Dummy = 0;
    auto operator<=>(const X& other) const
    {
        return Dummy <=> other.Dummy;
    }
    bool operator==(const X& other) const = default;
};
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.