Apa warna diatur sesuai dengan standar?
Menjawab dengan kutipan dari Standar C ++ 11 dan C ++ 14:
[expr.static.cast] / 10
Nilai tipe integral atau enumerasi dapat secara eksplisit dikonversi ke tipe enumerasi. Nilai tidak berubah jika nilai asli berada dalam kisaran nilai enumerasi (7.2). Jika tidak, nilai yang dihasilkan tidak ditentukan (dan mungkin tidak berada dalam kisaran itu).
Mari kita mencari rentang nilai enumerasi : [dcl.enum] / 7
Untuk enumerasi yang tipe dasarnya adalah tetap, nilai-nilai enumerasi adalah nilai-nilai dari tipe yang mendasarinya.
Sebelum CWG 1766 (C ++ 11, C ++ 14)
Oleh karena itu, untuk data[0] == 100
, nilai yang dihasilkan ditentukan (*), dan tidak ada Perilaku Tidak Terdefinisi (UB) yang terlibat. Lebih umum, saat Anda menggunakan dari tipe yang mendasari ke tipe enumerasi, tidak ada nilai dalam data[0]
dapat menyebabkan UB untuk static_cast
.
Setelah CWG 1766 (C ++ 17)
Lihat cacat CWG 1766 . Paragraf [expr.static.cast] p10 telah diperkuat, jadi Anda sekarang dapat memanggil UB jika Anda memberikan nilai yang berada di luar rentang yang dapat direpresentasikan dari enum ke tipe enum. Ini masih tidak berlaku untuk skenario dalam pertanyaan, karena data[0]
ini adalah tipe yang mendasari enumerasi (lihat di atas).
Harap dicatat bahwa CWG 1766 dianggap cacat dalam Standar, oleh karena itu diterima bagi pelaksana kompiler untuk menerapkan ke mode kompilasi C ++ 11 dan C ++ 14 mereka.
(*) char
harus memiliki lebar minimal 8 bit, tetapi tidak harus unsigned
. Nilai maksimum yang dapat disimpan harus paling tidak 127
per Lampiran E dari Standar C99.
Bandingkan dengan [expr] / 4
Jika selama evaluasi ekspresi, hasilnya tidak didefinisikan secara matematis atau tidak dalam kisaran nilai yang dapat diwakili untuk jenisnya, perilaku tidak terdefinisi.
Sebelum CWG 1766, tipe integral konversi -> tipe enumerasi dapat menghasilkan nilai yang tidak ditentukan . Pertanyaannya adalah: Dapatkah nilai yang tidak ditentukan berada di luar nilai yang dapat diwakili untuk jenisnya? Saya percaya jawabannya tidak - jika jawabannya adalah ya , tidak akan ada perbedaan dalam jaminan yang Anda dapatkan untuk operasi pada jenis yang ditandatangani antara "operasi ini menghasilkan nilai yang tidak ditentukan" dan "operasi ini memiliki perilaku yang tidak ditentukan".
Karenanya, sebelum CWG 1766, bahkan tidakstatic_cast<Color>(10000)
akan memanggil UB; tapi setelah CWG 1766, itu memang memanggil UB.
Sekarang, switch
pernyataannya:
[stmt.switch] / 2
Syaratnya harus tipe integral, tipe enumerasi, atau tipe kelas. [...] Promosi integral dilakukan.
[conv.prom] / 4
Nilai awal dari tipe pencacahan yang tidak dicentang yang jenis dasarnya adalah tetap (7.2) dapat dikonversi ke nilai awal dari jenis yang mendasarinya. Selain itu, jika promosi integral dapat diterapkan pada tipe yang mendasarinya, nilai awal dari tipe enumerasi yang tidak dicopot yang tipe dasarnya diperbaiki juga dapat dikonversi ke nilai awal dari tipe dasar yang dipromosikan.
Catatan: Tipe dasar dari scoped enum w / o enum-base adalah int
. Untuk enum yang tidak dicentang, tipe yang mendasarinya adalah implementasi yang ditentukan, tetapi tidak boleh lebih besar dari int
jika int
dapat berisi nilai-nilai semua enumerator.
Untuk enumerasi yang tidak dicentang , ini membawa kita ke / 1
Sebuah prvalue dari tipe integer selain bool
, char16_t
, char32_t
, atau wchar_t
yang bulat konversi rank (4.13) kurang dari pangkat int
dapat dikonversi ke prvalue jenis int
jika int
dapat mewakili semua nilai-nilai dari jenis sumber; jika tidak, prvalue sumber dapat dikonversi ke prvalue tipe unsigned int
.
Dalam kasus enumerasi yang tidak teropong , kita akan berurusan dengan int
s di sini. Untuk pencacahan dengan cakupan ( enum class
dan enum struct
), tidak ada promosi integral yang berlaku. Dengan cara apa pun, promosi integral tidak mengarah ke UB juga, karena nilai yang disimpan berada dalam kisaran jenis yang mendasarinya dan dalam kisaran int
.
[stmt.switch] / 5
Ketika switch
pernyataan dieksekusi, kondisinya dievaluasi dan dibandingkan dengan setiap kasus konstan. Jika salah satu konstanta kasus sama dengan nilai kondisi, kontrol dilewatkan ke pernyataan berikut case
label yang cocok . Jika tidak ada case
konstanta yang cocok dengan kondisinya, dan jika ada default
label, kontrol beralih ke pernyataan yang berlabel default
label.
The default
label harus memukul.
Catatan: Seseorang dapat melihat lagi pada operator perbandingan, tetapi tidak secara eksplisit digunakan dalam "perbandingan" yang dimaksud. Bahkan, tidak ada petunjuk bahwa ini akan memperkenalkan UB untuk enum yang dicakup atau tidak dicopot dalam kasus kami.
Sebagai bonus, apakah standar membuat jaminan seperti ini tetapi dengan enum sederhana?
Apakah enum
scoped atau tidak tidak ada bedanya di sini. Namun, itu membuat perbedaan apakah tipe yang mendasarinya tetap. Lengkap [decl.enum] / 7 adalah:
Untuk enumerasi yang tipe dasarnya adalah tetap, nilai-nilai enumerasi adalah nilai-nilai dari tipe yang mendasarinya. Jika tidak, untuk penghitungan di mana e min adalah yang terkecil pencacah dan e max adalah yang terbesar, nilai-nilai pencacahan adalah nilai-nilai di kisaran b min ke b max , didefinisikan sebagai berikut: Misalkan K
menjadi 1
untuk dua ini melengkapi representasi dan 0
untuk representasi komplemen atau sign-magnitude seseorang. b max adalah nilai terkecil lebih besar dari atau sama dengan max (| e min | - K
, | e max |) dan sama dengan 2M - 1 , di manaM
bilangan bulat non-negatif. b min adalah nol jika e min adalah non-negatif dan - (b max + K
) jika tidak.
Mari kita lihat enumerasi berikut:
enum ColorUnfixed /* no fixed underlying type */
{
red = 0x1,
yellow = 0x2
}
Perhatikan bahwa kami tidak dapat mendefinisikan ini sebagai enum yang dicakup, karena semua enum yang dicakup telah memperbaiki tipe yang mendasarinya.
Untungnya, ColorUnfixed
enumerator terkecil adalah red = 0x1
, jadi max (| e min | - K
, | e max |) sama dengan | e max | dalam hal apa pun, yaitu yellow = 0x2
. Nilai terkecil lebih besar atau sama dengan 2
, yang sama dengan 2 M - 1 untuk bilangan bulat positif M
adalah 3
( 2 2 - 1 ). (Saya pikir tujuannya adalah untuk memungkinkan kisaran sampai batas dalam 1-bit-langkah.) Oleh karena itu b max adalah 3
dan bmin adalah 0
.
Oleh karena itu, 100
akan berada di luar kisaran ColorUnfixed
, dan static_cast
akan menghasilkan nilai yang tidak ditentukan sebelum CWG 1766 dan perilaku yang tidak ditentukan setelah CWG 1766.
char
, jadi "Nilai tersebut tidak berubah jika nilai aslinya berada dalam kisaran nilai enumerasi (7.2)." berlaku.