Operator kesetaraan tidak dapat didefinisikan untuk implementasi operator pesawat ruang angkasa khusus di C ++ 20

51

Saya mengalami perilaku aneh dengan operator pesawat ruang angkasa baru <=>di C ++ 20. Saya menggunakan kompiler Visual Studio 2019 dengan /std:c++latest.

Kode ini dikompilasi dengan baik, seperti yang diharapkan:

#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;
}

Namun, jika saya mengubah X ke ini:

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

Saya mendapatkan kesalahan kompilator berikut:

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

Saya mencoba ini pada dentang juga, dan saya mendapatkan perilaku yang sama.

Saya akan menghargai beberapa penjelasan tentang mengapa implementasi standar menghasilkan operator==dengan benar, tetapi yang kustom tidak.

Zeenobit
sumber

Jawaban:

50

Ini dengan desain.

[class.compare.default] (penekanan saya)

3 Jika definisi kelas tidak secara eksplisit mendeklarasikan == fungsi operator, tetapi menyatakan fungsi operator perbandingan tiga arah yang default , ==fungsi operator dinyatakan secara implisit dengan akses yang sama dengan fungsi operator perbandingan tiga arah. ==Operator yang dideklarasikan secara implisit untuk kelas X adalah anggota inline dan didefinisikan sebagai default dalam definisi X.

Hanya default yang <=>memungkinkan disintesis ==ada. Alasannya adalah bahwa kelas suka std::vectortidak dapat menggunakan default <=>. Selain itu, menggunakan <=>untuk ==bukan cara yang paling efisien untuk membandingkan vektor. <=>harus memberikan pemesanan yang tepat, sedangkan ==dapat membayar lebih awal dengan membandingkan ukuran terlebih dahulu.

Jika suatu kelas melakukan sesuatu yang istimewa dalam perbandingan tiga-arahnya, ia mungkin perlu melakukan sesuatu yang istimewa di dalamnya ==. Jadi, alih-alih menghasilkan default yang tidak masuk akal, bahasa menyerahkannya kepada programmer.

StoryTeller - Unslander Monica
sumber
4
Ini tentu masuk akal, kecuali pesawat ruang angkasa adalah kereta. Meskipun secara potensial sangat tidak efisien ...
Deduplicator
1
@Deduplicator - Sensibility adalah subyektif. Beberapa orang akan mengatakan implementasi yang tidak efisien secara diam-diam dihasilkan menjadi tidak masuk akal.
StoryTeller - Unslander Monica
45

Selama standardisasi fitur ini, diputuskan bahwa kesetaraan dan pemesanan harus dipisahkan secara logis. Dengan demikian, penggunaan pengujian kesetaraan ( ==dan !=) tidak akan pernah diminta operator<=>. Namun, itu masih dianggap berguna untuk dapat default keduanya dengan satu deklarasi. Jadi jika Anda default operator<=>, diputuskan bahwa Anda juga bermaksud default operator==(kecuali Anda mendefinisikannya nanti atau telah mendefinisikannya sebelumnya).

Mengenai mengapa keputusan ini dibuat , alasan dasarnya seperti ini. Pertimbangkan std::string. Pemesanan dua string bersifat leksikografis; setiap karakter memiliki nilai integer dibandingkan dengan masing-masing karakter di string lain. Ketidaksetaraan pertama menghasilkan hasil pemesanan.

Namun, pengujian kesetaraan string memiliki hubungan arus pendek. Jika kedua string tidak memiliki panjang yang sama, maka tidak ada gunanya melakukan perbandingan karakter-bijaksana sama sekali; mereka tidak setara. Jadi, jika seseorang melakukan pengujian kesetaraan, Anda tidak ingin melakukannya dalam jangka panjang jika Anda dapat membuat hubungan pendek itu.

Ternyata banyak jenis yang membutuhkan pemesanan yang ditentukan pengguna juga akan menawarkan beberapa mekanisme hubungan pendek untuk pengujian kesetaraan. Untuk mencegah orang menerapkan saja operator<=>dan membuang potensi kinerja, kami secara efektif memaksa semua orang untuk melakukan keduanya.

Nicol Bolas
sumber
5
Ini adalah penjelasan yang jauh lebih baik daripada jawaban yang diterima
memo
17

Jawaban lain menjelaskan dengan sangat baik mengapa bahasanya seperti ini. Saya hanya ingin menambahkan bahwa jika itu tidak jelas, tentu saja mungkin untuk memiliki yang disediakan pengguna operator<=>dengan default operator==. Anda hanya perlu menulis secara default operator==:

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