Membandingkan dua contoh dari struct berikut ini, saya menerima kesalahan:
struct MyStruct1 {
MyStruct1(const MyStruct2 &_my_struct_2, const int _an_int = -1) :
my_struct_2(_my_struct_2),
an_int(_an_int)
{}
std::string toString() const;
MyStruct2 my_struct_2;
int an_int;
};
Kesalahannya adalah:
kesalahan C2678: binary '==': tidak ditemukan operator yang menggunakan operan kiri jenis 'myproj :: MyStruct1' (atau tidak ada konversi yang dapat diterima)
Mengapa?
c++
struct
comparison-operators
Jonathan
sumber
sumber
struct
kesetaraan Anda? Dan jika Anda menginginkan cara yang sederhana, selalu adamemcmp
terlalu lama struct Anda tidak berisi pointer.memcmp
gagal dengan anggota non-POD (sukastd::string
) dan struktur berlapis.==
operator --- dengan semantik yang hampir tidak pernah diinginkan. (Dan mereka tidak menyediakan sarana untuk menimpanya, jadi Anda akhirnya harus menggunakan fungsi anggota). Bahasa "modern" yang saya tahu juga tidak memberikan semantik nilai, jadi Anda terpaksa menggunakan pointer, meskipun tidak sesuai.operator=
(meskipun sering melakukan hal yang salah), karena alasan kompatibilitas C. Kompatibilitas C tidak membutuhkanoperator==
. Secara global, saya lebih suka apa yang dilakukan C ++ daripada apa yang dilakukan Java. (Saya tidak tahu C #, jadi mungkin itu lebih baik.)= default
!C ++ 20 diperkenalkan perbandingan default, alias "angkasa"
operator<=>
, yang memungkinkan Anda untuk permintaan compiler yang dihasilkan<
/<=
/==
/!=
/>=
/ dan / atau>
operator dengan (?) Pelaksanaan yang jelas / naif ...... tetapi Anda dapat menyesuaikannya untuk situasi yang lebih rumit (dibahas di bawah). Lihat di sini untuk proposal bahasa, yang berisi pembenaran dan diskusi. Jawaban ini tetap relevan untuk C ++ 17 dan sebelumnya, dan untuk wawasan tentang kapan Anda harus menyesuaikan penerapan
operator<=>
....Tampaknya agak tidak membantu C ++ untuk tidak menstandarkan ini sebelumnya, tetapi seringkali struct / class memiliki beberapa anggota data untuk dikecualikan dari perbandingan (misalnya penghitung, hasil yang di-cache, kapasitas penampung, keberhasilan operasi terakhir / kode kesalahan, kursor), seperti serta keputusan yang harus diambil tentang banyak hal termasuk namun tidak terbatas pada:
int
mungkin menghilangkan 99% objek yang tidak sama dengan sangat cepat, sementaramap<string,string>
anggota mungkin sering memiliki entri yang identik dan relatif mahal untuk dibandingkan - jika nilai dimuat pada waktu proses, pemrogram mungkin memiliki wawasan kompiler tidak mungkinvector
,list
), dan jika demikian apakah boleh untuk mengurutkannya di tempat sebelum membandingkan vs. menggunakan memori ekstra untuk mengurutkan temporer setiap kali perbandingan dilakukanunion
akan dibandingkanoperator==
dirinya sendiri (tetapi mungkin memilikicompare()
atauoperator<
ataustr()
atau getter ...)Jadi, agak menyenangkan untuk memiliki kesalahan sampai Anda secara eksplisit memikirkan tentang apa arti perbandingan untuk struktur spesifik Anda, daripada membiarkannya terkompilasi tetapi tidak memberi Anda hasil yang berarti pada waktu proses .
Semua yang dikatakan, akan lebih baik jika C ++ membiarkan Anda mengatakan
bool operator==() const = default;
ketika Anda memutuskan==
tes anggota-demi-anggota yang "naif" tidak apa - apa. Sama untuk!=
. Beberapa anggota diberikan / basa, "default"<
,<=
,>
, dan>=
implementasi tampak putus asa meskipun - Cascading atas dasar urutan deklarasi ini mungkin tapi sangat tidak mungkin apa yang ingin, mengingat bertentangan imperatif untuk anggota memesan (basa menjadi tentu sebelum anggota, pengelompokan oleh aksesibilitas, konstruksi / penghancuran sebelum penggunaan bergantung). Agar lebih bermanfaat secara luas, C ++ akan membutuhkan sistem anotasi anggota / basis data baru untuk memandu pilihan - itu akan menjadi hal yang hebat untuk dimiliki dalam Standar, idealnya digabungkan dengan pembuatan kode yang ditentukan pengguna berbasis AST ... Saya harap Itu'Implementasi khas dari operator kesetaraan
Implementasi yang masuk akal
Ini kemungkinan bahwa implementasi yang wajar dan efisien akan menjadi:
Catatan bahwa ini membutuhkan
operator==
untukMyStruct2
juga.Implikasi dari implementasi ini, dan alternatifnya, dibahas di bawah judul Diskusi spesifik MyStruct1 Anda di bawah ini.
Pendekatan yang konsisten untuk ==, <,> <= dll
Sangat mudah untuk memanfaatkan
std::tuple
operator perbandingan untuk membandingkan instance kelas Anda sendiri - cukup gunakanstd::tie
untuk membuat tupel referensi ke bidang dalam urutan perbandingan yang diinginkan. Menggeneralisasikan contoh saya dari sini :Saat Anda "memiliki" (yaitu dapat mengedit, faktor dengan lib perusahaan dan pihak ketiga) kelas yang ingin Anda bandingkan, dan terutama dengan kesiapan C ++ 14 untuk menyimpulkan jenis kembalian fungsi dari
return
pernyataan, sering kali lebih baik menambahkan " ikat "fungsi anggota ke kelas yang ingin Anda bandingkan:Kemudian perbandingan di atas disederhanakan menjadi:
Jika Anda menginginkan kumpulan operator perbandingan yang lebih lengkap, saya sarankan operator tingkatkan (cari
less_than_comparable
). Jika tidak cocok karena alasan tertentu, Anda mungkin menyukai atau tidak menyukai gagasan makro dukungan (online) :... yang kemudian dapat digunakan a la ...
(Versi dasi anggota C ++ 14 di sini )
Diskusi spesifik MyStruct1 Anda
Ada implikasi pada pilihan untuk memberikan status bebas versus anggota
operator==()
...Implementasi berdiri bebas
Anda harus membuat keputusan yang menarik. Karena kelas Anda dapat secara implisit dibangun dari a
MyStruct2
, fungsi berdiri bebas / non-anggotabool operator==(const MyStruct2& lhs, const MyStruct2& rhs)
akan mendukung ...... dengan terlebih dahulu membuat temporary
MyStruct1
frommy_myStruct2
, lalu melakukan perbandingan. Ini pasti akan meninggalkanMyStruct1::an_int
set ke nilai parameter default konstruktor-1
. Tergantung pada apakah Anda termasukan_int
perbandingan dalam pelaksanaan Andaoperator==
, sebuahMyStruct1
kekuatan atau mungkin tidak membandingkan sama denganMyStruct2
itu sendiri membandingkan sama denganMyStruct1
'smy_struct_2
anggota! Lebih lanjut, membuat sementaraMyStruct1
bisa menjadi operasi yang sangat tidak efisien, karena melibatkan penyalinanmy_struct2
anggota yang ada ke sementara, hanya untuk membuangnya setelah perbandingan. (Tentu saja, Anda dapat mencegah konstruksi implisitMyStruct1
s ini untuk perbandingan dengan membuat konstruktor tersebutexplicit
atau menghapus nilai default untukan_int
.)Implementasi anggota
Jika Anda ingin menghindari konstruksi implisit
MyStruct1
dari aMyStruct2
, jadikan operator perbandingan sebagai fungsi anggota:Perhatikan
const
kata kunci - hanya diperlukan untuk implementasi anggota - menyarankan compiler bahwa membandingkan objek tidak mengubahnya, jadi dapat diizinkan padaconst
objek.Membandingkan representasi yang terlihat
Terkadang cara termudah untuk mendapatkan jenis perbandingan yang Anda inginkan adalah ...
... yang seringkali juga sangat mahal - semua
string
itu dibuat dengan susah payah hanya untuk dibuang! Untuk tipe dengan nilai floating point, membandingkan representasi yang terlihat berarti jumlah digit yang ditampilkan menentukan toleransi di mana nilai yang hampir sama diperlakukan sama selama perbandingan.sumber
int cmp(x, y)
ataucompare
fungsi mengembalikan nilai negatif untukx < y
, 0 untuk kesetaraan dan nilai positif bagix > y
digunakan sebagai dasar untuk<
,>
,<=
,>=
,==
, dan!=
; sangat mudah menggunakan CRTP untuk memasukkan semua operator tersebut ke dalam kelas. Saya yakin saya telah memposting implementasi dalam jawaban lama, tetapi tidak dapat menemukannya dengan cepat.>
,<=
dan>=
dalam hal<
. Anda juga bisa mengimplementasikan==
dan dengan!=
cara itu, tapi itu biasanya bukan implementasi yang sangat efisien. Akan lebih baik jika tidak ada CRTP atau trik lain yang diperlukan untuk semua ini, tetapi standar hanya akan mengamanatkan pembuatan otomatis operator ini jika tidak secara eksplisit ditentukan oleh pengguna dan<
ditentukan.==
dan!=
mungkin tidak diekspresikan secara efisien dengan<
menggunakan bandingkan untuk semuanya adalah umum. "Akan lebih baik jika tidak ada CRTP atau trik lainnya akan diperlukan" - mungkin, tapi kemudian CRTP dapat dengan mudah digunakan untuk menghasilkan banyak operator lain (misalnya bitwise|
,&
,^
dari|=
,&=
dan^=
;+
-
*
/
%
dari bentuk-bentuk tugas mereka; biner-
dari negasi unary dan+
) - begitu banyak variasi yang berpotensi berguna pada tema ini sehingga hanya menyediakan fitur bahasa untuk satu bagian yang cukup acak yang tidak terlalu elegan.std::tie
untuk melakukan perbandingan beberapa anggota?Anda perlu secara eksplisit menentukan
operator ==
untukMyStruct1
.Sekarang perbandingan == legal untuk 2 objek tersebut.
sumber
Mulai di C ++ 20, itu harus mungkin untuk menambahkan set lengkap operator perbandingan default (
==
,<=
, dll) untuk kelas dengan mendeklarasikan bawaan operator perbandingan tiga arah ( "angkasa" operator), seperti ini:Dengan kompiler C ++ 20 yang sesuai, menambahkan baris tersebut ke MyStruct1 dan MyStruct2 mungkin cukup untuk memungkinkan perbandingan kesetaraan, dengan asumsi definisi MyStruct2 kompatibel.
sumber
Perbandingan tidak berfungsi pada struct di C atau C ++. Bandingkan menurut bidang.
sumber
Secara default struct tidak memiliki
==
operator. Anda harus menulis implementasi Anda sendiri:sumber
Di luar kotak, operator == hanya berfungsi untuk primitif. Agar kode Anda berfungsi, Anda perlu membebani operator == untuk struct Anda.
sumber
Karena Anda tidak menulis operator perbandingan untuk struct Anda. Kompilator tidak membuatnya untuk Anda, jadi jika Anda ingin perbandingan, Anda harus menulisnya sendiri.
sumber