Tại sao trình biên dịch C ++ không định nghĩa toán tử == và toán tử! =?


302

Tôi là một fan hâm mộ lớn của việc để trình biên dịch làm nhiều việc cho bạn nhất có thể. Khi viết một lớp đơn giản, trình biên dịch có thể cung cấp cho bạn những thứ sau đây là 'miễn phí':

  • Một constructor mặc định (trống)
  • Một constructor sao chép
  • Một kẻ hủy diệt
  • Một toán tử gán ( operator=)

Nhưng nó dường như không thể cung cấp cho bạn bất kỳ toán tử so sánh nào - chẳng hạn như operator==hoặc operator!=. Ví dụ:

class foo
{
public:
    std::string str_;
    int n_;
};

foo f1;        // Works
foo f2(f1);    // Works
foo f3;
f3 = f2;       // Works

if (f3 == f2)  // Fails
{ }

if (f3 != f2)  // Fails
{ }

Có một lý do tốt cho việc này? Tại sao thực hiện so sánh giữa các thành viên là một vấn đề? Rõ ràng nếu lớp phân bổ bộ nhớ thì bạn muốn cẩn thận, nhưng đối với một lớp đơn giản chắc chắn trình biên dịch có thể làm điều này cho bạn?


4
Tất nhiên, cũng là kẻ hủy diệt được cung cấp miễn phí.
Johann Gerell

23
Trong một trong những cuộc nói chuyện gần đây của mình, Alex Stepanov đã chỉ ra rằng thật sai lầm khi không có tự động mặc định ==, giống như cách có gán tự động mặc định ( =) trong một số điều kiện nhất định. (Đối số về con trỏ không nhất quán vì logic áp dụng cho cả ===và không chỉ cho lần thứ hai).
alfC

2
@becko Đây là một trong loạt bài tại A9: youtube.com/watch?v=k-meLQaYP5Y , tôi không nhớ trong các cuộc đàm phán nào. Ngoài ra còn có một đề nghị rằng nó có vẻ là làm theo cách của mình để C ++ 17 open-std.org/JTC1/SC22/WG21/docs/papers/2016/p0221r0.html
alfC

1
@becko, đây là một trong những phần đầu tiên trong loạt bài "Lập trình hiệu quả với các thành phần" hoặc "Cuộc trò chuyện lập trình" cả ở A9, có sẵn trên Youtube.
alfC

1
@becko Trên thực tế, có một câu trả lời dưới đây chỉ ra quan điểm của Alex stackoverflow.com/a/23329089/225186
alfC

Câu trả lời:


71

Trình biên dịch sẽ không biết bạn muốn so sánh con trỏ hay so sánh sâu (bên trong).

An toàn hơn là không thực hiện nó và để cho lập trình viên tự làm điều đó. Sau đó, họ có thể thực hiện tất cả các giả định mà họ thích.


292
Vấn đề đó không ngăn nó tạo ra một ctor sao chép, nơi nó khá có hại.
MSalters

78
Sao chép các hàm tạo (và operator=) thường hoạt động trong cùng bối cảnh với các toán tử so sánh - nghĩa là, có một kỳ vọng rằng sau khi bạn thực hiện a = b, a == blà đúng. Nó chắc chắn có ý nghĩa đối với trình biên dịch để cung cấp một mặc định operator==bằng cách sử dụng cùng một ngữ nghĩa giá trị tổng hợp như nó làm operator=. Tôi nghi ngờ paercebal thực sự chính xác ở đây trong đó operator=(và ctor sao chép) chỉ được cung cấp cho khả năng tương thích C và họ không muốn làm cho tình hình tồi tệ hơn.
Pavel Minaev

46
-1. Tất nhiên bạn muốn so sánh sâu, nếu lập trình viên muốn so sánh con trỏ, anh ta sẽ viết (& f1 == & f2)
Viktor Sehr

62
Viktor, tôi đề nghị bạn suy nghĩ lại phản ứng của bạn. Nếu lớp Foo chứa Bar *, thì trình biên dịch sẽ biết liệu Foo :: toán tử == muốn so sánh địa chỉ của Bar * hay nội dung của Bar?
Đánh dấu Ingram

46
@Mark: Nếu nó chứa một con trỏ, so sánh các giá trị con trỏ là hợp lý - nếu nó chứa một giá trị, so sánh các giá trị là hợp lý. Trong trường hợp đặc biệt, lập trình viên có thể ghi đè. Điều này giống như ngôn ngữ thực hiện so sánh giữa ints và con trỏ với int.
Eamon Nerbonne

317

Đối số nếu trình biên dịch có thể cung cấp một hàm tạo sao chép mặc định, thì nó có thể cung cấp một mặc định tương tự operator==()có ý nghĩa nhất định. Tôi nghĩ rằng lý do cho quyết định không cung cấp mặc định do trình biên dịch tạo cho toán tử này có thể được đoán bởi những gì Stroustrup nói về hàm tạo sao chép mặc định trong "Thiết kế và tiến hóa của C ++" (Phần 11.4.1 - Kiểm soát sao chép) :

Cá nhân tôi cho rằng thật đáng tiếc rằng các hoạt động sao chép được xác định theo mặc định và tôi cấm sao chép các đối tượng của nhiều lớp của tôi. Tuy nhiên, C ++ thừa hưởng các hàm tạo và gán sao chép mặc định từ C và chúng thường được sử dụng.

Vì vậy, thay vì "tại sao C ++ không có mặc định operator==()?", Câu hỏi nên là "tại sao C ++ có hàm gán và sao chép mặc định?", Với câu trả lời là các mục đó được Stroustrup đưa vào một cách miễn cưỡng để tương thích ngược với C (có lẽ là nguyên nhân của hầu hết các mụn cóc của C ++, nhưng cũng có thể là lý do chính cho sự phổ biến của C ++).

Đối với mục đích riêng của tôi, trong IDE của tôi, đoạn mã tôi sử dụng cho các lớp mới chứa các khai báo cho một toán tử gán riêng và hàm tạo sao chép để khi tôi tạo một lớp mới, tôi không nhận được các thao tác sao chép và gán mặc định - Tôi phải loại bỏ khai báo một cách rõ ràng trong số các hoạt động từ private:phần đó nếu tôi muốn trình biên dịch có thể tạo chúng cho tôi.


29
Câu trả lời tốt. Tôi chỉ muốn chỉ ra rằng trong C ++ 11, thay vì làm cho toán tử gán và sao chép hàm riêng tư, bạn có thể xóa chúng hoàn toàn như thế này: Foo(const Foo&) = delete; // no copy constructorFoo& Foo=(const Foo&) = delete; // no assignment operator
karadoc

9
"Tuy nhiên, C ++ đã kế thừa các hàm tạo và sao chép mặc định của nó từ C" Điều đó không ngụ ý tại sao bạn phải tạo TẤT CẢ các loại C ++ theo cách này. Đáng lẽ họ chỉ nên giới hạn điều này với các POD cũ đơn giản, chỉ là các loại đã có trong C, không còn nữa.
thesaint

3
Tôi chắc chắn có thể hiểu tại sao C ++ thừa hưởng những hành vi này struct, nhưng tôi ước rằng nó để classhành xử khác đi (và hoàn toàn). Trong quá trình, nó cũng sẽ có một sự khác biệt có ý nghĩa hơn giữa structclassbên cạnh truy cập mặc định.
jamesdlin

@jamesdlin Nếu bạn muốn một quy tắc, việc vô hiệu hóa khai báo ngầm và định nghĩa của các hàm và gán nếu một dtor được khai báo sẽ có ý nghĩa nhất.
Ded repeatator

1
Tôi vẫn không thấy bất kỳ tác hại nào trong việc cho phép lập trình viên ra lệnh rõ ràng trình biên dịch để tạo một operator==. Tại thời điểm này, nó chỉ là cú pháp đường cho một số mã nồi hơi. Nếu bạn sợ rằng theo cách này, lập trình viên có thể bỏ qua một số con trỏ giữa các trường lớp, bạn có thể thêm một điều kiện là nó chỉ có thể hoạt động trên các kiểu và đối tượng nguyên thủy có chính các toán tử đẳng thức. Không có lý do để không cho phép điều này hoàn toàn, mặc dù.
NO_NAME

93

Ngay cả trong C ++ 20, trình biên dịch vẫn sẽ không tạo ra operator==cho bạn

struct foo
{
    std::string str;
    int n;
};

assert(foo{"Anton", 1} == foo{"Anton", 1}); // ill-formed

Nhưng bạn sẽ có được khả năng mặc định rõ ràng == kể từ C ++ 20 :

struct foo
{
    std::string str;
    int n;

    // either member form
    bool operator==(foo const&) const = default;
    // ... or friend form
    friend bool operator==(foo const&, foo const&) = default;
};

Mặc định ==thực hiện thành viên khôn ngoan ==(giống như cách mà trình xây dựng sao chép mặc định thực hiện xây dựng sao chép thành viên khôn ngoan). Các quy tắc mới cũng cung cấp mối quan hệ mong đợi giữa ==!=. Ví dụ, với khai báo ở trên, tôi có thể viết cả hai:

assert(foo{"Anton", 1} == foo{"Anton", 1}); // ok!
assert(foo{"Anton", 1} != foo{"Anton", 2}); // ok!

Tính năng cụ thể này (mặc định operator==và đối xứng giữa ==!=) xuất phát từ một đề xuất là một phần của tính năng ngôn ngữ rộng hơn operator<=>.


Bạn có biết nếu có bất kỳ cập nhật gần đây về điều này? Nó sẽ có sẵn trong c ++ 17?
dcmm88

3
@ dcmm88 Thật không may, nó sẽ không có sẵn trong C ++ 17. Tôi đã cập nhật câu trả lời.
Anton Savin

2
Một đề xuất sửa đổi cho phép điều tương tự (ngoại trừ mẫu ngắn) sẽ có trong C ++ 20 mặc dù :)
Rakete1111

Vì vậy, về cơ bản bạn phải xác định = default, đối với những thứ không được tạo theo mặc định, phải không? Nghe có vẻ như oxymoron đối với tôi ("mặc định rõ ràng").
artin

@artin Có ý nghĩa khi thêm các tính năng mới vào ngôn ngữ sẽ không phá vỡ triển khai hiện có. Thêm tiêu chuẩn thư viện mới hoặc trình biên dịch những thứ mới có thể làm là một điều. Thêm các chức năng thành viên mới mà trước đây chúng không tồn tại là câu chuyện hoàn toàn khác. Để đảm bảo dự án của bạn khỏi những sai lầm, nó sẽ đòi hỏi nhiều nỗ lực hơn. Cá nhân tôi thích cờ trình biên dịch để chuyển giữa mặc định rõ ràng và ẩn. Bạn xây dựng dự án từ tiêu chuẩn C ++ cũ hơn, sử dụng mặc định rõ ràng bằng cờ trình biên dịch. Bạn đã cập nhật trình biên dịch vì vậy bạn nên cấu hình nó đúng cách. Đối với các dự án mới làm cho nó ẩn.
Maciej Załucki

44

IMHO, không có lý do "tốt". Lý do có rất nhiều người đồng ý với quyết định thiết kế này là vì họ không học cách làm chủ sức mạnh của ngữ nghĩa dựa trên giá trị. Mọi người cần phải viết rất nhiều hàm tạo sao chép tùy chỉnh, toán tử so sánh và hàm hủy vì chúng sử dụng các con trỏ thô trong quá trình thực hiện.

Khi sử dụng các con trỏ thông minh thích hợp (như std :: shared_ptr), hàm tạo sao chép mặc định thường ổn và việc triển khai rõ ràng của toán tử so sánh mặc định giả định sẽ tốt.


39

Nó đã trả lời C ++ không làm == vì C không có, và đây là lý do tại sao C chỉ cung cấp mặc định = nhưng không == ở vị trí đầu tiên. C muốn giữ cho nó đơn giản: C thực hiện = bởi memcpy; tuy nhiên, == không thể được thực hiện bởi memcmp do phần đệm. Vì phần đệm không được khởi tạo, memcmp nói rằng chúng khác nhau mặc dù chúng giống nhau. Vấn đề tương tự tồn tại đối với lớp trống: memcmp nói rằng chúng khác nhau vì kích thước của các lớp trống không bằng không. Có thể thấy từ trên rằng việc triển khai == phức tạp hơn so với triển khai = trong C. Một số ví dụ mã liên quan đến việc này. Sửa chữa của bạn được đánh giá cao nếu tôi sai.


6
C ++ không sử dụng memcpy cho operator=- nó chỉ hoạt động với các loại POD, nhưng C ++ cũng cung cấp mặc định operator=cho các loại không POD.
Flexo

2
Vâng, C ++ đã thực hiện = theo cách tinh vi hơn. Có vẻ như C chỉ thực hiện = với một memcpy đơn giản.
Cánh Rio

Nội dung của câu trả lời này nên được đặt cùng với Michael's. Ông sửa câu hỏi sau đó câu trả lời này.
Sgene9

27

Trong video này Alex Stepanov, người tạo ra STL giải quyết câu hỏi này vào khoảng 13:00. Tóm lại, khi theo dõi sự phát triển của C ++, ông lập luận rằng:

  • Thật không may rằng == và! = Không được tuyên bố ngầm (và Bjarne đồng ý với anh ta). Một ngôn ngữ chính xác sẽ có sẵn những điều đó cho bạn (anh ấy tiếp tục đề xuất rằng bạn không thể xác định a ! = Điều đó phá vỡ ngữ nghĩa của == )
  • Lý do đây là trường hợp có nguồn gốc của nó (như nhiều vấn đề về C ++) trong C. Ở đó, toán tử gán được định nghĩa ngầm định bằng bit by bit gán nhưng điều đó sẽ không hoạt động cho == . Một lời giải thích chi tiết hơn có thể được tìm thấy trong bài viết này từ Bjarne Stroustrup.
  • Trong câu hỏi tiếp theo Tại sao khi đó không phải là thành viên do so sánh thành viên sử dụng , anh ta nói một điều đáng kinh ngạc : C là một ngôn ngữ trong nhà và anh chàng thực hiện những thứ này cho Ritchie nói với anh rằng anh ta thấy điều này khó thực hiện!

Sau đó, ông nói rằng trong tương lai (xa) ==! = Sẽ được tạo ngầm.


2
có vẻ như tương lai xa này sẽ không phải là 2017 hay 18, cũng không phải 19, bạn cũng bắt được sự trôi dạt của tôi ...
UmNyobe

18

C ++ 20 cung cấp một cách để dễ dàng thực hiện một toán tử so sánh mặc định.

Ví dụ từ cppreference.com :

class Point {
    int x;
    int y;
public:
    auto operator<=>(const Point&) const = default;
    // ... non-comparison functions ...
};

// compiler implicitly declares operator== and all four relational operators work
Point pt1, pt2;
if (pt1 == pt2) { /*...*/ } // ok, calls implicit Point::operator==
std::set<Point> s; // ok
s.insert(pt1); // ok
if (pt1 <= pt2) { /*...*/ } // ok, makes only a single call to Point::operator<=>

4
Tôi ngạc nhiên khi họ sử dụng Pointlàm ví dụ cho thao tác đặt hàng , vì không có cách mặc định hợp lý nào để đặt hai điểm xytọa độ ...
đường ống

4
@pipe Nếu bạn không quan tâm đến thứ tự các yếu tố, sử dụng toán tử mặc định có ý nghĩa. Ví dụ: bạn có thể sử dụng std::setđể đảm bảo tất cả các điểm là duy nhất và chỉ std::setsử dụng operator<.
vll

Về loại trả về auto: Đối với trường hợp này, chúng ta có thể luôn cho rằng nó sẽ std::strong_orderingđến từ #include <compare>đâu không?
kevinarpe

1
@kevinarpe Kiểu trả về là std::common_comparison_category_t, cho lớp này trở thành thứ tự mặc định ( std::strong_ordering).
vll

15

Không thể xác định mặc định ==, nhưng bạn có thể xác định mặc định !=thông qua ==đó bạn thường nên tự xác định. Đối với điều này, bạn nên làm những điều sau đây:

#include <utility>
using namespace std::rel_ops;
...

class FooClass
{
public:
  bool operator== (const FooClass& other) const {
  // ...
  }
};

Bạn có thể xem http://www.cplusplus.com/reference/std/utility/rel_ops/ để biết chi tiết.

Ngoài ra, nếu bạn xác định operator< , các toán tử cho <=,>,> = có thể được suy ra từ nó khi sử dụng std::rel_ops.

Nhưng bạn nên cẩn thận khi sử dụng std::rel_opsvì các toán tử so sánh có thể được suy ra cho các loại bạn không mong đợi.

Cách ưa thích hơn để suy ra toán tử liên quan từ cơ bản là sử dụng toán tử boost :: .

Cách tiếp cận được sử dụng trong boost là tốt hơn bởi vì nó xác định việc sử dụng toán tử cho lớp bạn chỉ muốn, không phải cho tất cả các lớp trong phạm vi.

Bạn cũng có thể tạo "+" từ "+ =", - từ "- =", v.v ... (xem danh sách đầy đủ tại đây )


Tôi đã không nhận được mặc định !=sau khi viết ==toán tử. Hoặc tôi đã làm nhưng nó thiếu const. Phải tự viết nó và tất cả đều tốt.
John

bạn có thể chơi với const-ness để đạt được kết quả cần thiết. Không có mã, thật khó để nói điều gì sai với nó.
sergtk

2
Có một lý do rel_opskhông được chấp nhận trong C ++ 20: bởi vì nó không hoạt động , ít nhất là không phải ở mọi nơi và chắc chắn là không nhất quán. Không có cách nào đáng tin cậy sort_decreasing()để biên dịch. Mặt khác, Boost.Operators hoạt động và luôn hoạt động.
Barry

10

C ++ 0x đã có một đề xuất cho các chức năng mặc định, vì vậy bạn có thể nói rằng default operator==; chúng tôi đã học được rằng nó giúp làm cho những điều này rõ ràng.


3
Tôi nghĩ rằng chỉ có "các hàm thành viên đặc biệt" (hàm tạo mặc định, hàm tạo sao chép, toán tử gán và hàm hủy) có thể được mặc định rõ ràng. Họ đã mở rộng điều này cho một số nhà khai thác khác?
Michael Burr

4
Move constructor cũng có thể được mặc định, nhưng tôi không nghĩ điều này áp dụng cho operator==. Đó là một điều đáng tiếc.
Pavel Minaev

5

Về mặt khái niệm không dễ để xác định sự bình đẳng. Ngay cả đối với dữ liệu POD, người ta có thể lập luận rằng ngay cả khi các trường giống nhau, nhưng nó là một đối tượng khác nhau (tại một địa chỉ khác), nó không nhất thiết phải bằng nhau. Điều này thực sự phụ thuộc vào cách sử dụng của các nhà điều hành. Thật không may, trình biên dịch của bạn không phải là ngoại cảm và không thể suy ra điều đó.

Bên cạnh đó, các chức năng mặc định là những cách tuyệt vời để tự bắn vào chân mình. Mặc định bạn mô tả về cơ bản là ở đó để giữ khả năng tương thích với các cấu trúc POD. Tuy nhiên, chúng gây ra quá nhiều sự tàn phá với các nhà phát triển mà quên chúng hoặc ngữ nghĩa của các triển khai mặc định.


10
Không có sự mơ hồ đối với các cấu trúc POD - chúng nên hành xử chính xác giống như bất kỳ loại POD nào khác, đó là sự bình đẳng giá trị (chứ không phải là đẳng thức tham chiếu). Một cái intđược tạo thông qua ctor sao chép từ cái khác bằng với cái mà nó được tạo ra; điều hợp lý duy nhất để làm cho một structtrong hai intlĩnh vực là làm việc theo cùng một cách chính xác.
Pavel Minaev

1
@mgiuca: Tôi có thể thấy sự hữu ích đáng kể cho mối quan hệ tương đương phổ quát sẽ cho phép bất kỳ loại nào hoạt động như một giá trị được sử dụng làm khóa trong từ điển hoặc bộ sưu tập tương tự. Tuy nhiên, các bộ sưu tập như vậy không thể hành xử hữu ích mà không có mối quan hệ tương đương phản xạ được đảm bảo. IMHO, giải pháp tốt nhất sẽ là xác định một toán tử mới mà tất cả các kiểu dựng sẵn có thể triển khai hợp lý và xác định một số loại con trỏ mới giống như các kiểu con trỏ hiện tại ngoại trừ một số sẽ xác định đẳng thức là tương đương tham chiếu trong khi các loại khác sẽ nối với mục tiêu toán tử tương đương.
supercat

1
@supercat Bằng cách tương tự, bạn có thể đưa ra lập luận gần như giống nhau cho +toán tử ở chỗ nó không liên kết với phao; đó là (x + y) + z! = x + (y + z), do cách làm tròn số FP xảy ra. (Có thể cho rằng đây là một vấn đề tồi tệ hơn nhiều so với ==vì nó đúng với các giá trị số thông thường.) Bạn có thể đề xuất thêm một toán tử bổ sung mới hoạt động cho tất cả các loại số (thậm chí int) và gần như chính xác +nhưng nó có liên quan ( bằng cách nào đó). Nhưng sau đó, bạn sẽ thêm sự phình to và nhầm lẫn vào ngôn ngữ mà không thực sự giúp được nhiều người.
mgiuca 13/03/2015

1
@mgiuca: Có những thứ khá giống nhau ngoại trừ trường hợp cạnh thường cực kỳ hữu ích và những nỗ lực sai lầm để tránh những thứ đó dẫn đến sự phức tạp không cần thiết. Nếu mã máy khách đôi khi sẽ cần xử lý các trường hợp cạnh một cách và đôi khi cần xử lý chúng theo cách khác, có một phương thức cho mỗi kiểu xử lý sẽ loại bỏ rất nhiều mã xử lý trường hợp cạnh trong máy khách. Đối với sự tương tự của bạn, không có cách nào để xác định hoạt động trên các giá trị dấu phẩy động có kích thước cố định để mang lại kết quả bắc cầu trong mọi trường hợp (mặc dù một số ngôn ngữ của thập niên 1980 có ngữ nghĩa tốt hơn ...
supercat

1
... hơn ngày nay về vấn đề đó) và do đó, việc họ không làm điều không thể không phải là một điều ngạc nhiên. Tuy nhiên, không có trở ngại cơ bản nào trong việc thực hiện mối quan hệ tương đương có thể áp dụng chung cho bất kỳ loại giá trị nào có thể được sao chép.
supercat

1

Có một lý do tốt cho việc này? Tại sao thực hiện so sánh giữa các thành viên là một vấn đề?

Nó có thể không phải là một vấn đề chức năng, nhưng về mặt hiệu suất, so sánh giữa các thành viên mặc định có thể được tối ưu hóa hơn so với phân công / sao chép thành viên mặc định. Không giống như thứ tự chuyển nhượng, thứ tự so sánh ảnh hưởng đến hiệu suất vì thành viên bất bình đẳng đầu tiên ngụ ý phần còn lại có thể được bỏ qua. Vì vậy, nếu có một số thành viên thường bằng nhau, bạn muốn so sánh họ lần cuối và trình biên dịch không biết thành viên nào có nhiều khả năng bằng nhau.

Xem xét ví dụ này, nơi verboseDescriptionmột chuỗi dài được chọn từ một tập hợp các mô tả thời tiết có thể tương đối nhỏ.

class LocalWeatherRecord {
    std::string verboseDescription;
    std::tm date;
    bool operator==(const LocalWeatherRecord& other){
        return date==other.date
            && verboseDescription==other.verboseDescription;
    // The above makes a lot more sense than
     // return verboseDescription==other.verboseDescription
     //     && date==other.date;
    // because some verboseDescriptions are liable to be same/similar
    }
}

(Tất nhiên trình biên dịch sẽ có quyền bỏ qua thứ tự so sánh nếu nó nhận ra rằng chúng không có tác dụng phụ, nhưng có lẽ nó vẫn sẽ lấy hàng đợi từ mã nguồn nơi nó không có thông tin tốt hơn.)


Nhưng không ai ngăn bạn viết một so sánh tối ưu do người dùng xác định nếu bạn thấy có vấn đề về hiệu suất. Theo kinh nghiệm của tôi đó sẽ là một thiểu số rất nhỏ của các trường hợp mặc dù.
Peter - Phục hồi Monica

1

Để câu trả lời cho câu hỏi này vẫn hoàn thành khi thời gian trôi qua: vì C ++ 20, nó có thể được tạo tự động bằng lệnh auto operator<=>(const foo&) const = default;

Nó sẽ tạo ra tất cả các toán tử: == ,! =, <, <=,> Và> =, xem https://en.cppreference.com/w/cpp/lingu/default_comparisons để biết chi tiết.

Do cái nhìn của người vận hành <=>, nó được gọi là toán tử tàu vũ trụ. Xem thêm Tại sao chúng ta cần toán tử tàu vũ trụ <=> trong C ++? .

EDIT: cũng trong C ++ 11, một thay thế khá gọn gàng có sẵn với std::tiexem https://en.cppreference.com/w/cpp/utility/tuple/tie để biết ví dụ mã hoàn chỉnh với bool operator<(…). Phần thú vị, được thay đổi để làm việc với ==là:

#include <tuple>

struct S {
………
bool operator==(const S& rhs) const
    {
        // compares n to rhs.n,
        // then s to rhs.s,
        // then d to rhs.d
        return std::tie(n, s, d) == std::tie(rhs.n, rhs.s, rhs.d);
    }
};

std::tie hoạt động với tất cả các toán tử so sánh và được trình biên dịch hoàn toàn tối ưu hóa.


-1

Tôi đồng ý, đối với các lớp loại POD thì trình biên dịch có thể làm điều đó cho bạn. Tuy nhiên những gì bạn có thể coi đơn giản là trình biên dịch có thể bị sai. Vì vậy, tốt hơn là để cho các lập trình viên làm điều đó.

Tôi đã có trường hợp POD một lần khi hai trong số các trường là duy nhất - vì vậy một so sánh sẽ không bao giờ được coi là đúng. Tuy nhiên, so sánh tôi chỉ cần so sánh về tải trọng - thứ mà trình biên dịch sẽ không bao giờ hiểu hoặc có thể tự mình tìm ra.

Bên cạnh đó - họ không mất nhiều thời gian để viết phải không?!

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.