Apa yang dimaksud dengan operator <=> di C ++?

214

Ketika saya mencoba mempelajari tentang operator C ++ , saya menemukan sebuah operator perbandingan aneh di cppreference.com , * dalam tabel yang terlihat seperti ini:

masukkan deskripsi gambar di sini

"Yah, jika ini adalah operator umum di C ++, saya lebih baik mempelajarinya", pikir saya. Tetapi semua upaya saya untuk menjelaskan misteri ini tidak berhasil. Bahkan di sini, di Stack Overflow, saya tidak beruntung dalam pencarian saya.

Apakah ada koneksi antara <=> dan C ++ ?

Dan jika ada, apa tepatnya yang dilakukan operator ini?

* Sementara itu cppreference.com memperbarui halaman itu dan sekarang berisi informasi tentang <=>operator.

qlp
sumber
82
@haccks: Oh, tolong, kami punya banyak pertanyaan tentang hal-hal yang bahkan tidak dipilih ke dalam standar. Kami memiliki tag C ++ 20 karena suatu alasan. Hal-hal semacam ini sangat sesuai dengan topik.
Nicol Bolas
1
@ cubuspl42 bar< foo::operator<=>adalah contoh bagaimana bisa seperti <--operator.
Yakk - Adam Nevraumont
8
@haccks: Benar. Seperti C ++ 11 adalah tag tentang kompiler yang mengimplementasikan C ++ 11. Dan C ++ 14 adalah tag tentang kompiler yang mengimplementasikan C ++ 14. Dan C ++ 17 adalah tentang kompiler yang mengimplementasikan C ++ 17. Tidak, C ++ 20 adalah tag untuk hal-hal tentang C ++ 20. Dan karena pertanyaan ini tentang C ++ 20, itu dia. Tag wiki yang salah, bukan tag itu sendiri.
Nicol Bolas

Jawaban:

179

Ini disebut operator perbandingan tiga arah .

Menurut proposal makalah P0515 :

Ada operator perbandingan tiga arah baru <=>,. Ekspresi a <=> bmengembalikan objek yang membandingkan <0jika a < b, membandingkan >0jika a > b, dan membandingkan ==0jika adan bsama / setara.

Untuk menulis semua perbandingan untuk jenis Anda, tulis saja operator<=>yang mengembalikan jenis kategori yang sesuai:

  • Kembali sebuah _ordering jika jenis Anda secara alami mendukung <, dan kami akan efisien menghasilkan <, >, <=, >=, ==, dan !=; jika tidak, kembalikan _equality , dan kami akan menghasilkan == dan ! = secara efisien .

  • Kembalilah kuat jika untuk tipe Anda a == bmenyiratkan f(a) == f(b)(dapat disubstitusikan, di mana f hanya membaca keadaan yang menonjol perbandingan dapat diakses menggunakan antarmuka const nonprivate), jika tidak kembalikan lemah.

The cppreference mengatakan:

Ekspresi operator perbandingan tiga arah memiliki formulir

lhs <=> rhs   (1)  

Ekspresi mengembalikan objek itu

  • membandingkan <0jikalhs < rhs
  • membandingkan >0jikalhs > rhs
  • dan membandingkan ==0jika lhsdan rhssama / setara.
msc
sumber
93
Bagi mereka yang bingung (seperti saya) tentang apa artinya "membandingkan <0", "membandingkan >0", dan "membandingkan ==0", mereka berarti <=>pengembalian nilai negatif, positif, atau nol, tergantung pada argumen. Sangat mirip strncmpdan memcmp.
Cornstalks
1
@ Hai meskipun keduanya 'a' < 'a'dan 'c' < 'a'keduanya salah, 'a' < 'a'dan 'a' < 'c'tidak. DALAM urutan pemesanan yang kuat adalah benar: a != ba < b || b < a
Revolver_Ocelot
1
@Revolver_Ocelot Ah, sehingga dapat didefinisikan / dihasilkan sebagai operator==(T x, T y) { return !(x < y) && !(y < x); }dan operator!=(T x, T y) { return (x < y) || (y < x); }- ah-ha! Tentu saja ini kurang efisien daripada yang benar ==karena meminta perbandingan dua kali, tetapi masih rapi.
Dai
3
Apa yang dimaksud dengan "kembali kuat" dan "kembali lemah"?
lucidbrot
2
@ hkBattousai itu berarti bahwa objek kembali, jika dibandingkan akan < 0bernilai true. Artinya, jika a < bkemudian (a <=> b) < 0selalu benar.
rmobis
116

Pada 2017-11-11 , komite ISO C ++ mengadopsi proposal Herb Sutter untuk operator perbandingan tiga arah <=> "pesawat ruang angkasa" sebagai salah satu fitur baru yang ditambahkan ke C ++ 20 . Dalam makalah berjudul Sutter perbandingan Konsisten , Maurer dan Brown mendemonstrasikan konsep-konsep desain baru. Untuk ikhtisar proposal, berikut adalah kutipan dari artikel:

Ekspresi a <=> b mengembalikan objek yang membandingkan <0 jika a <b , membandingkan > 0 jika a> b , dan membandingkan == 0 jika a dan b sama / setara.

Kasus umum: Untuk menulis semua perbandingan untuk tipe X Anda dengan tipe Y , dengan semantik anggota, cukup tulis:

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

Kasus tingkat lanjut: Untuk menulis semua perbandingan untuk tipe X Anda dengan tipe Y , cukup tulis operator <=> yang menggunakan Y , dapat menggunakan = default untuk mendapatkan semantik yang sesuai dengan anggota jika diinginkan, dan mengembalikan jenis kategori yang sesuai:

  • Kembalikan _ordering jika jenis Anda secara alami mendukung < , dan kami akan secara efisien menghasilkan simetris < , > , <= , > = , == , dan ! = ; jika tidak mengembalikan _equality , dan kami akan menghasilkan symmetric == dan ! = secara efisien .
  • Kembalikan strong_ jika untuk tipe Anda a == b menyiratkan f (a) == f (b) (dapat disubstitusikan, di mana f hanya membaca keadaan yang menonjol perbandingan yang dapat diakses menggunakan anggota const publik ), jika tidak kembalikan lemah_ .

Kategori Perbandingan

Lima kategori perbandingan didefinisikan sebagai std::tipe, masing-masing memiliki nilai yang telah ditentukan sebelumnya:

+--------------------------------------------------------------------+
|                  |          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 |             |
+------------------+------+------------+---------------+-------------+

Konversi tersirat di antara jenis-jenis ini didefinisikan sebagai berikut:

  • strong_orderingdengan nilai-nilai { less, equal, greater} implisit mengkonversi ke:
    • weak_orderingdengan nilai-nilai { less, equivalent, greater}
    • partial_orderingdengan nilai-nilai { less, equivalent, greater}
    • strong_equalitydengan nilai-nilai { unequal, equal, unequal}
    • weak_equalitydengan nilai-nilai { nonequivalent, equivalent, nonequivalent}
  • weak_orderingdengan nilai-nilai { less, equivalent, greater} implisit mengkonversi ke:
    • partial_orderingdengan nilai-nilai { less, equivalent, greater}
    • weak_equalitydengan nilai-nilai { nonequivalent, equivalent, nonequivalent}
  • partial_orderingdengan nilai-nilai { less, equivalent, greater, unordered} implisit mengkonversi ke:
    • weak_equalitydengan nilai-nilai { nonequivalent, equivalent, nonequivalent, nonequivalent}
  • strong_equalitydengan nilai { equal, unequal} secara implisit dikonversi ke:
    • weak_equalitydengan nilai { equivalent, nonequivalent}

Perbandingan tiga arah

The <=>token diperkenalkan. Urutan karakter <=>menjadi tokenizes <= >, dalam kode sumber lama. Misalnya, X<&Y::operator<=>perlu menambahkan ruang untuk mempertahankan maknanya.

Operator kelebihan beban <=>adalah fungsi perbandingan tiga arah dan memiliki prioritas lebih tinggi dari <dan lebih rendah dari <<. Ini mengembalikan jenis yang dapat dibandingkan dengan literal 0tetapi jenis kembali lainnya diizinkan seperti untuk mendukung templat ekspresi. Semua <=>operator yang didefinisikan dalam bahasa dan di perpustakaan standar mengembalikan salah satu dari 5 std::jenis kategori perbandingan yang disebutkan di atas .

Untuk jenis bahasa, <=>perbandingan built-in dengan jenis yang sama disediakan. Semua adalah constexpr , kecuali jika disebutkan sebaliknya. Perbandingan ini tidak dapat dilakukan secara heterogen menggunakan promosi / konversi skalar.

  • Untuk bool, integral, dan tipe penunjuk, <=>pengembalian strong_ordering.
  • Untuk tipe penunjuk, berbagai kualifikasi-cv dan konversi turunan ke basis diizinkan untuk memanggil built-in yang homogen <=>, dan ada built-in yang heterogen operator<=>(T*, nullptr_t). Hanya perbandingan pointer ke objek / alokasi yang sama yang merupakan ekspresi konstan.
  • Untuk tipe floating point yang mendasar, <=>pengembalian partial_ordering, dan dapat dipanggil secara heterogen dengan memperluas argumen ke tipe floating point yang lebih besar.
  • Untuk enumerasi, <=>kembalikan sama dengan tipe dasar enumerasi <=>.
  • Untuk nullptr_t, <=>pengembalian , strong_orderingdan selalu hasil equal.
  • Untuk array menyatakan bahwa pihak, T[N] <=> T[N]mengembalikan jenis yang sama seperti T's <=>dan Melakukan perbandingan elementwise leksikografis. Tidak ada <=>untuk array lainnya.
  • Karena voidtidak ada <=>.

Untuk lebih memahami cara kerja bagian dalam operator ini, silakan baca makalah aslinya . Ini adalah apa yang saya temukan menggunakan mesin pencari.

qlp
sumber
1
Seolah cpp belum cukup kompleks. Mengapa tidak menulis metode perbandingan saja ...
Leandro
6
@Leandro Operator pesawat ruang angkasa adalah metode perbandingan itu. Selain itu, ini Hanya Bekerja dan menulis (atau menghapus) enam operator perbandingan lainnya. Saya akan mengambil satu fungsi operator perbandingan yang dituliskan di atas enam pelat boiler individu.
Anonim
Perhatikan bahwa _equalitytipe - tipe itu mati: ternyata <=>cocok dengan empat operator relasional tetapi tidak juga dengan dua operator kesetaraan (walaupun ada beberapa gula sintaksis yang kuat untuk mendukung kasus umum di mana Anda menginginkan semuanya).
Davis Herring
12

Jawaban ini menjadi tidak relevan karena halaman web yang dirujuk telah berubah

The web page Anda referensi rusak. Itu sedang banyak diedit hari itu dan bagian yang berbeda tidak sinkron. Status ketika saya melihatnya adalah:

Di bagian atas halaman ini daftar operator perbandingan yang ada saat ini (dalam C ++ 14). Tidak ada <=>disana.

Di bagian bawah halaman, mereka seharusnya mendaftar operator yang sama, tetapi mereka melakukan kesalahan dan menambahkan saran ini di masa depan.

gccbelum tahu tentang <=>(dan dengan -std=c++14, tidak akan pernah), jadi menurut Anda maksud Anda a <= > b. Ini menjelaskan pesan kesalahan.

Jika Anda mencoba hal yang sama lima tahun dari sekarang, Anda mungkin akan mendapatkan pesan kesalahan yang lebih baik, seperti <=> not part of C++14.

Stig Hemmer
sumber
1
Halaman OP link ke benar, seperti halaman terpisah yang Anda tautkan. Ini memenuhi syarat <=>operator dengan label (karena C ++ 20), memberi tahu Anda versi standar mana yang diharapkan. Pelabelan standar adalah konvensi yang diikuti oleh cppreference.com. Tentu saja Anda tidak memiliki kompiler yang kembali dalam mesin waktu untuk mendukungnya untuk Anda, tetapi cpprefernce memberi tahu Anda (dengan benar) apa yang diharapkan.
Spencer
Ya, tapi ... Bukan jawaban. Anda berkomentar ... atau sesuatu.
qlp
2
Saya bermaksud untuk menautkan ke halaman web yang sama dengan pertanyaan, tetapi tidak terjawab. Saya pikir saya telah menjawab bagian dari pertanyaan yang tidak dijawab oleh jawaban lain. Saya mengabaikan pertanyaan utama yang berani karena yang lain sudah menjawabnya.
Stig Hemmer