Jenis pengembalian '?:' (Operator kondisional ternary)

208

Mengapa yang pertama mengembalikan referensi?

int x = 1;
int y = 2;
(x > y ? x : y) = 100;

Sedangkan yang kedua tidak?

int x = 1;
long y = 2;
(x > y ? x : y) = 100;

Sebenarnya, yang kedua tidak mengkompilasi sama sekali - "bukan nilai yang tersisa dari penugasan".

Yola
sumber
1
hmm, itu seperti menemukan kasus khusus untuk memanggang roti, tidak pernah datang ke sini sekali
Ulterior
Karena menugaskan suatu tipe pada ekspresi akan menyiratkan pemeran setidaknya satu istilah, istilah ini tidak akan lagi menjadi nilai-l.
Yves Daoust

Jawaban:

173

Ekspresi tidak memiliki tipe pengembalian, mereka memiliki tipe dan - seperti yang dikenal dalam standar C ++ terbaru - kategori nilai.

Ekspresi bersyarat dapat berupa lvalue atau rvalue . Ini adalah kategori nilainya. (Ini agak penyederhanaan, karena C++11kami memiliki nilai, nilai, dan nilai.)

Dalam istilah yang sangat luas dan sederhana, sebuah lvalue mengacu pada obyek dalam memori dan nilai p hanya nilai yang mungkin belum tentu dilampirkan ke obyek dalam memori.

Sebuah ekspresi tugas memberikan nilai ke suatu objek sehingga hal yang sedang ditugaskan untuk harus menjadi lvalue .

Agar ekspresi kondisional ( ?:) menjadi nilai (sekali lagi, dalam istilah yang luas dan sederhana), operan kedua dan ketiga harus merupakan nilai dari tipe yang sama . Ini karena jenis dan kategori nilai ekspresi kondisional ditentukan pada waktu kompilasi dan harus sesuai apakah kondisinya benar atau tidak. Jika salah satu operan harus dikonversi ke jenis yang berbeda agar sesuai dengan yang lain maka ekspresi bersyarat tidak dapat menjadi nilai karena hasil konversi ini tidak akan menjadi nilai .

Referensi ISO / IEC 14882: 2011:

3.10 [basic.lval] Lvalues ​​dan rvalues ​​(tentang kategori nilai)

5.15 [expr.cond] Operator kondisional (aturan untuk jenis dan kategori nilai apa yang dimiliki ekspresi kondisional)

5.17 [expr.ass] Operator penugasan dan majemuk (persyaratan bahwa lhs penugasan harus merupakan nilai yang dapat dimodifikasi)

CB Bailey
sumber
3
Dan ketika membaca xvalue dan prvalue (karena saya belum pernah mendengarnya sebelum jawaban Anda), saya menemukan posting SO yang praktis ini: stackoverflow.com/questions/3601602/…
fluffy
an rvalue is just a value that may not necessarily be *attached* to an object in memory.Bisakah Anda menjelaskan ini dengan istilah yang lebih sederhana? . Juga apa maksudmu type and value *category*? Terima kasih
Mr.Anubis
@ SoulReaper: prvalue, xvalue, glvalueadalah kategori nilai.
Xeo
@ Xeo Saya menghargai bantuan tetapi dapatkah Anda memberi tahu apa yang ia maksud dengan nilai hanya nilai yang mungkin tidak harus dilampirkan ke objek dalam memori. ? dengan contoh?
Mr.Anubis
@SoulReaper: Saya pikir dia berbicara tentang hal-hal seperti true, this, enumnilai-nilai. Hal-hal itu adalah nilai-nilai (nilai-nilai "murni"), tetapi tidak hidup dalam ingatan.
Xeo
57

Jenis ?:ekspresi terner adalah tipe umum dari argumen kedua dan ketiga. Jika kedua jenisnya sama, Anda mendapatkan referensi kembali. Jika mereka dapat dikonversi satu sama lain, yang satu dipilih dan yang lain dikonversi (dipromosikan dalam kasus ini). Karena Anda tidak dapat mengembalikan referensi nilai ke sementara (variabel yang dikonversi / dipromosikan), tipenya adalah tipe nilai.

Xeo
sumber
tetapi y lebih besar dari x, jadi tidak perlu dalam promosi untuk kasus khusus ini, ia dapat mengembalikan referensi ke y. Hmm ... Tapi saya setuju, itu akan aneh.
Yola
1
@ Mr.TAMER: Saya lebih suka menggali melalui standar. : <
Xeo
3
@Yola: Sejak jenis adalah konsep waktu kompilasi di C ++, kembalinya sebenarnya nilai dari ekspresi tidak masalah.
Xeo
1
Anda tidak mendapatkan referensi kembali, Anda mendapatkan nilai.
Suma
1
@ Xeo: Tidak dalam terminologi C ++, meskipun;)
Sebastian Mach
19

Itu tidak dapat mengembalikan nilai karena itu harus secara implisit mempromosikan jenis xuntuk mencocokkan jenis y(karena kedua belah pihak :bukan dari jenis yang sama), dan dengan itu ia harus membuat sementara.


Apa yang dikatakan standar? ( n1905 )

Ekspresi 5.17 Operator penugasan dan tugas majemuk

5.17 / 3

Jika operan kedua dan ketiga memiliki jenis yang berbeda, dan salah satu dari keduanya memiliki jenis kelas (mungkin cv-kualifikasi), upaya dilakukan untuk mengkonversi masing-masing operan tersebut ke jenis yang lain. Proses untuk menentukan apakah ekspresi operan E1 dari tipe T1 dapat dikonversi agar sesuai dengan ekspresi operan E2 dari tipe T2 didefinisikan sebagai berikut:

- Jika E2 adalah lvalue: E1 dapat dikonversi untuk mencocokkan E2 jika E1 dapat secara implisit dikonversi (klausa 4) ke jenis "referensi ke T2", tunduk pada batasan bahwa dalam konversi referensi harus mengikat langsung (8.5.3 ) ke E1.

- Jika E2 adalah nilai, atau jika konversi di atas tidak dapat dilakukan:

- jika E1 dan E2 memiliki tipe kelas, dan tipe kelas yang mendasarinya sama atau satu adalah kelas dasar yang lain: E1 dapat dikonversi agar sesuai dengan E2 jika kelas T2 adalah jenis yang sama dengan, atau kelas dasar dari , kelas T1, dan kualifikasi cv T2 adalah kualifikasi cv yang sama dengan, atau kualifikasi cv yang lebih besar daripada, kualifikasi cv T1. Jika konversi diterapkan, E1 diubah menjadi nilai tipe T2 yang masih merujuk ke objek kelas sumber asli (atau sub-objek yang sesuai daripadanya). [ Catatan: artinya, tidak ada salinan yang dibuat. - end note ] dengan menyalin-inisialisasi temporer tipe T2 dari E1 dan menggunakan temporer itu sebagai operan yang dikonversi.

Kalau tidak (yaitu, jika E1atau E2 memiliki tipe non kelas, atau jika keduanya memiliki tipe kelas tetapi kelas yang mendasari tidak sama atau satu kelas dasar yang lain): E1 dapat dikonversi untuk mencocokkan E2 jika E1 dapat secara implisit dikonversi ke tipe yang akan dimiliki ekspresi E2 jika E2 dikonversi ke nilai (atau tipe yang dimilikinya, jika E2 adalah nilai).

Dengan menggunakan proses ini, ditentukan apakah operan kedua dapat dikonversi agar sesuai dengan operan ketiga, dan apakah operan ketiga dapat dikonversi agar sesuai dengan operan kedua. Jika keduanya dapat dikonversi, atau satu dapat dikonversi tetapi konversinya ambigu, programnya salah bentuk. Jika tidak ada yang dapat dikonversi, operan dibiarkan tidak berubah dan pemeriksaan lebih lanjut dilakukan seperti yang dijelaskan di bawah ini. Jika tepat satu konversi dimungkinkan, konversi itu diterapkan ke operan yang dipilih dan operan yang dikonversi digunakan sebagai pengganti operan asli untuk sisa bagian ini.


5.17 / 4

Jika operan kedua dan ketiga adalah lvalues ​​dan memiliki tipe yang sama, hasilnya adalah dari tipe itu dan merupakan nilai dan itu adalah bidang-bit jika operan kedua atau ketiga adalah bidang-bit, atau jika keduanya bit- bidang.


5.17 / 5

Kalau tidak, hasilnya adalah nilai. Jika operan kedua dan ketiga tidak memiliki jenis yang sama, dan salah satu dari keduanya memiliki jenis kelas (mungkin cv-kualifikasi), resolusi kelebihan digunakan untuk menentukan konversi (jika ada) untuk diterapkan pada operan (13.3.1.2, 13.6) . Jika resolusi kelebihan gagal, program ini salah bentuk. Jika tidak, konversi yang ditentukan diterapkan, dan operan yang dikonversi digunakan sebagai pengganti operan asli untuk sisa bagian ini.

Filip Roséen - ref
sumber