Jawaban ini sepertinya tidak mencakup masalah yang intmungkin tidak cukup besar! ( [C++03: 7.2/5])
Lightness Races in Orbit
Menariknya, Anda dapat menentukan operator++pada enum; Namun, jadi Anda bisa melakukannya for(Enum_E e = (Enum_E)0; e < ENUM_COUNT; e++). Catatan Anda harus cor 0untuk Enum_Ekarena operator C ++ larang tugas pada enum.
weberc2
Jika ada operator waktu kompilasi, mirip dengan cara sizeof bekerja, yang dapat memancarkan literal std :: initializer_list yang terdiri dari nilai-nilai enum, kami akan memiliki solusi dan tidak akan melibatkan overhead runtime.
Harap dicatat, enum Lastdimaksudkan untuk dilewati oleh iterasi. Dengan menggunakan Lastenum "palsu" ini , Anda tidak harus memperbarui kondisi terminating di dalam for loop ke enum "real" terakhir setiap kali Anda ingin menambahkan enum baru. Jika Anda ingin menambahkan lebih banyak enum nanti, cukup tambahkan sebelum Terakhir. Loop dalam contoh ini masih akan berfungsi.
Tentu saja, ini rusak jika nilai enum ditentukan:
enumFoo{One=1,Two=9,Three=4,Last};
Ini menggambarkan bahwa enum tidak dimaksudkan untuk diulangi. Cara khas untuk menangani enum adalah menggunakannya dalam pernyataan pergantian.
Perhatikan bahwa, pada bagian pertama dari contoh, jika Anda ingin menggunakan 'i' sebagai Foo enum dan bukan int, Anda perlu melakukan pelepasan statis seperti: static_cast <Foo> (i)
Clayton
5
Anda juga melewatkan Terakhir di loop. Harus <= Terakhir
Tony
20
@Tony Last dimaksudkan untuk dilewati. Jika Anda ingin menambahkan lebih banyak enums nanti, tambahkan sebelum Last ... loop pada contoh pertama masih berfungsi. Dengan menggunakan enum "palsu" Terakhir, Anda tidak harus memperbarui kondisi terminating Anda dalam loop untuk enum "nyata" terakhir setiap kali Anda ingin menambahkan enum baru.
timidpueo
Kecuali sekarang Anda telah mengalokasikan memori saat enum, asalkan tidak diindeks dan benar-benar kontinu, dapat melakukan tugas itu tanpa mengalokasikan memori.
Awan
1
Perhatikan bahwa untuk definisi enum ini aman untuk pembaruan, orang harus menentukan nilai UNKNOWN = 0. Selain itu, saya akan menyarankan untuk hanya menjatuhkan defaultcase ketika beralih nilai enum karena mungkin menyembunyikan kasus-kasus di mana penanganan nilai-nilai dilupakan sampai runtime. Sebagai gantinya, seseorang harus meng-hardcode semua nilai dan menggunakan UNKNOWNbidang untuk mendeteksi ketidaksesuaian.
Benjamin Bannier
53
#include<iostream>#include<algorithm>namespaceMyEnum{enumType{
a =100,
b =220,
c =-1};staticconstTypeAll[]={ a, b, c };}void fun(constMyEnum::Type e ){
std::cout << e << std::endl;}int main(){// allfor(constauto e :MyEnum::All)
fun( e );// somefor(constauto e :{MyEnum::a,MyEnum::b })
fun( e );// all
std::for_each( std::begin(MyEnum::All), std::end(MyEnum::All), fun );return0;}
Terima kasih! Perhatikan bahwa jika Anda memotong file / kelas dan jika kompatibilitas MS memberi Anda masalah dengan konstanta non-integer yang dinyatakan header, ini membantu di bawah kompiler saya untuk secara eksplisit menempatkan ukuran dalam jenis di header: static const Type All[3];dan kemudian saya bisa untuk menginisialisasi dalam sumber: const MyEnum::Type MyEnum::All[3] = { a, b, c }; Sebelum melakukan itu, saya mendapatkan Error in range-based for...kesalahan menjengkelkan (karena array memiliki ukuran yang tidak diketahui). Menemukan ini berkat jawaban terkait
bijak
1
Versi array sangat bersahabat dengan copy paste. Selain jawaban yang paling memuaskan, "TIDAK" atau "hanya untuk urutan". Bahkan mungkin ramah makro.
Paulo Neves
1
ini mungkin merupakan solusi yang baik untuk enum dengan jumlah item yang sedikit, tetapi untuk enum dengan jumlah item yang besar itu tidak boleh cocok.
kato2
20
Jika enum Anda mulai dengan 0 dan kenaikan selalu 1.
Dengan c ++ 11, sebenarnya ada alternatif: menulis iterator kustom templatized sederhana.
mari kita asumsikan enum Anda
enumclass foo {
one,
two,
three
};
Kode generik ini akan melakukan triknya, cukup efisien - tempatkan di header generik, itu akan membantu Anda untuk setiap enum yang mungkin perlu Anda ulangi:
#include<type_traits>template<typename C, C beginVal, C endVal>classIterator{typedeftypename std::underlying_type<C>::type val_t;int val;public:Iterator(const C & f): val(static_cast<val_t>(f)){}Iterator(): val(static_cast<val_t>(beginVal)){}Iteratoroperator++(){++val;return*this;}
C operator*(){returnstatic_cast<C>(val);}Iterator begin(){return*this;}//default ctor is goodIterator end(){staticconstIterator endIter=++Iterator(endVal);// cache itreturn endIter;}booloperator!=(constIterator& i){return val != i.val;}};
Dan kemudian Anda bisa beralih menggunakan range-for
for(foo i : fooIterator()){//notice the parentheses!
do_stuff(i);}
Asumsi bahwa Anda tidak memiliki celah di enum Anda masih benar; tidak ada asumsi pada jumlah bit yang sebenarnya diperlukan untuk menyimpan nilai enum (terima kasih kepada std :: underlying_type)
Saya tidak tahu mengapa ini diturunkan. Ini solusi yang masuk akal.
Paul Brannan
11
Saya berharap itu karena entri perlu dipertahankan di dua tempat.
Semut
Apakah C ++ mengizinkan for (NodePosition pos : NodePositionVector)sintaks? Sejauh yang saya tahu ini adalah sintaks Java, dan Anda akan memerlukan iterator di C ++ untuk melakukan sesuatu yang setara.
thegreatjedi
3
@thegreatjedi Sejak C ++ 11 Anda dapat, bahkan lebih sederhana: untuk (pos otomatis: NodePositionVector) {..}
Enzojz
@ thegreatjedi Akan lebih cepat untuk mencari, atau bahkan menyusun program pengujian, daripada mengajukan pertanyaan itu. Tapi ya, karena C ++ 11 itu adalah sintaks C ++ yang benar-benar valid, yang diterjemahkan oleh kompiler ke kode yang setara (dan jauh lebih verbose / kurang abstrak), biasanya melalui iterator; lihat Preferensi Cp . Dan, seperti kata Enzojz, C ++ 11 juga ditambahkan auto, jadi Anda tidak harus mendeklarasikan jenis elemen secara eksplisit, kecuali jika Anda (A) perlu menggunakan operator konversi atau (B) tidak suka autokarena suatu alasan . Sebagian besar forpengguna rentang menggunakan autoAFAICT
underscore_d
9
Saya sering melakukannya seperti itu
enumEMyEnum{
E_First,
E_Orange = E_First,
E_Green,
E_White,
E_Blue,
E_Last
}for(EMyEnum i = E_First; i < E_Last; i =EMyEnum(i +1)){}
atau jika tidak berturut-turut, tetapi dengan langkah reguler (mis. bendera bit)
Untuk menggunakan enum untuk membuat bitmask. mis., gabungkan beberapa opsi dalam variabel tunggal, kemudian gunakan FOR untuk menguji setiap opsi. Memperbaiki posting saya dengan contoh yang lebih baik.
Niki
Saya masih belum bisa menggunakannya (& pos Anda masih menunjukkan contoh lama)! Menggunakan enum sebagai bitmasks sangat membantu, tetapi tidak dapat menghubungkan titik-titik! bisa tolong jelaskan sedikit dalam contoh Anda secara detail, Anda dapat memasukkan kode tambahan juga.
Anu
@anu Maaf tidak melihat komentar Anda. Menambahkan kelas Frog sebagai contoh bitmask
Niki
8
Anda tidak bisa dengan enum. Mungkin enum bukan yang paling cocok untuk situasi Anda.
Sebuah konvensi umum adalah untuk memberi nama nilai enum terakhir seperti MAX dan menggunakannya untuk mengontrol loop menggunakan int.
Ada beberapa contoh di sini yang menunjukkan yang sebaliknya. Saya sendiri pernyataan Anda, Anda bertentangan dengan diri sendiri (baris kedua).
Niki
6
Sesuatu yang belum tercakup dalam jawaban lain = jika Anda menggunakan enums C ++ 11 yang diketik dengan kuat, Anda tidak dapat menggunakan ++atau menggunakannya + int. Dalam hal ini, sedikit solusi berantakan diperlukan:
enumCount{ zero, one, two, three };
for_range (Count, c, zero, three){
cout <<"forward: "<< c << endl;}
Ini dapat digunakan untuk beralih mundur dan maju melalui unsigned, integer, enums dan chars:
for_range (unsigned, i,10,0){
cout <<"backwards i: "<< i << endl;}
for_range (char, c,'z','a'){
cout << c << endl;}
Meskipun definisi canggung itu dioptimalkan dengan sangat baik. Saya melihat disassembler di VC ++. Kode ini sangat efisien. Jangan menunda tetapi ketiganya untuk pernyataan: kompiler hanya akan menghasilkan satu loop setelah optimasi! Anda bahkan dapat mendefinisikan loop tertutup:
unsigned p[4][5];
for_range (Count, i, zero,three)
for_range(unsignedint, j,4,0){
p[i][j]=static_cast<unsigned>(i)+j;}
Anda jelas tidak dapat mengulangi melalui tipe yang disebutkan dengan kesenjangan.
Kelebihan kenaikan / penurunan mengharuskan Anda membuat keputusan tentang apa yang harus dilakukan ketika ada luapan
Eponim
3
Dengan asumsi bahwa enum diberi nomor secara berurutan adalah rawan kesalahan. Selain itu, Anda mungkin ingin beralih hanya menggunakan enumerator terpilih. Jika bagian itu kecil, mengulanginya secara eksplisit mungkin merupakan pilihan yang elegan:
enumItem{Man,Wolf,Goat,Cabbage};// or enum classfor(auto item :{Wolf,Goat,Cabbage}){// or Item::Wolf, ...// ...}
Ini adalah opsi yang bagus menurut saya. Harus menjadi bagian dari spesifikasi C ++ yang lebih baru daripada yang saya gunakan ketika saya mengajukan pertanyaan yang saya duga?
Adam
Iya. Itu berulang melalui std :: initializer_list <Item>. tautan .
marski
2
Jika Anda tidak ingin mencemari Anda enum dengan item COUNT akhir (karena mungkin jika Anda juga menggunakan enum dalam sebuah saklar, maka kompiler akan memperingatkan Anda tentang kasus COUNT yang hilang :), Anda dapat melakukan ini:
enumColour{Red,Green,Blue};constColourLastColour=Blue;Colour co(0);while(true){// do stuff with co// ...if(co ==LastColour)break;
co =Colour(co+1);}
Inilah solusi lain yang hanya berfungsi untuk enum yang berdekatan. Ini memberikan iterasi yang diharapkan, kecuali untuk keburukan dalam kenaikan, yang merupakan tempatnya, karena itulah yang rusak di C ++.
enumBar{One=1,Two,Three,End_Bar// Marker for end of enum; };for(Bar foo =One; foo <End_Bar; foo =Bar(foo +1)){// ...}
Penambahan bisa disingkat menjadi foo = Bar(foo + 1).
HolyBlackCat
Terima kasih, HolyBlackCat, saya telah memasukkan saran luar biasa Anda! Saya juga memperhatikan bahwa Riot memiliki cukup banyak solusi yang sama, tetapi sesuai dengan pengetikan yang kuat (dan karenanya lebih bertele-tele).
Ethan Bradford
2
enumclass A {
a0=0, a3=3, a4=4};constexpr std::array<A,3> ALL_A {A::a0, A::a3, A::a4};// constexpr is important herefor(A a: ALL_A){if(a==A::a0 || a==A::a4) std::cout <<static_cast<int>(a);}
SEBUAH constexpr std::array dapat mengulang bahkan enum non-sekuensial tanpa array yang dipakai oleh kompiler. Ini tergantung pada hal-hal seperti heuristik optimisasi kompiler dan apakah Anda mengambil alamat array.
Dalam percobaan saya, saya menemukan bahwa g++9,1 dengan -O3akan mengoptimalkan array di atas jika ada 2 nilai non-sekuensial atau beberapa nilai sekuensial (saya menguji hingga 6). Tetapi ini hanya berlaku jika Anda memiliki ifpernyataan. (Saya mencoba pernyataan yang membandingkan nilai integer lebih besar dari semua elemen dalam array berurutan dan itu menggarisbawahi iterasi meskipun tidak ada yang dikecualikan, tetapi ketika saya meninggalkan pernyataan if, nilai-nilai itu dimasukkan ke dalam memori.) nilai dari enum non-sekuensial dalam [satu kasus | https://godbolt.org/z/XuGtoc] . Saya menduga perilaku aneh ini adalah karena heuristik yang mendalam berkaitan dengan cache dan prediksi cabang.
Saya suka semantik rentang-seperti-untuk-loop sederhana dan saya pikir itu akan berkembang bahkan itulah sebabnya saya suka solusi ini.
rtischer8277
2
Dalam buku bahasa pemrograman C ++ dari Bjarne Stroustrup, Anda dapat membaca bahwa ia mengusulkan untuk membebani buku operator++khusus Anda enum. enumapakah tipe yang ditentukan pengguna dan operator kelebihan beban ada dalam bahasa untuk situasi khusus ini.
Anda dapat membuat kode berikut:
#include<iostream>enumclassColors{red, green, blue};Colors&operator++(Colors&c,int){switch(c){caseColors::red:return c=Colors::green;caseColors::green:return c=Colors::blue;caseColors::blue:return c=Colors::red;// managing overflowdefault:throw std::exception();// or do anything else to manage the error...}}int main(){Colors c =Colors::red;// casting in int just for convenience of output.
std::cout <<(int)c++<< std::endl;
std::cout <<(int)c++<< std::endl;
std::cout <<(int)c++<< std::endl;
std::cout <<(int)c++<< std::endl;
std::cout <<(int)c++<< std::endl;return0;}
Pikiran yang saya gunakan enum class. Kode berfungsi dengan baik enumjuga. Tapi saya lebih suka enum classkarena mereka diketik dengan kuat dan dapat mencegah kita melakukan kesalahan pada waktu kompilasi.
Downvote dilakukan pada pos ini. Ada alasan mengapa itu tidak akan menjawab pertanyaan?
LAL
Alasannya mungkin karena ini adalah solusi yang mengerikan secara arsitektur: itu memaksa Anda untuk menulis logika global yang dimaksudkan untuk diikat ke komponen tertentu (enumerasi Anda), apalagi jika enumerasi Anda berubah karena alasan apa pun Anda terpaksa mengedit + Anda. + operator juga, sebagai pendekatan yang tidak berkelanjutan untuk proyek skala menengah-besar, itu tidak mengherankan itu berasal dari rekomendasi Bjarne Stroustrup, kembali pada hari-hari arsitektur perangkat lunak seperti fiksi ilmiah
Manjia
Pertanyaan awal adalah tentang memiliki operator ke enum. Itu bukan pertanyaan arsitektur. Saya tidak percaya bahwa pada 2013 C ++ adalah fiksi ilmiah.
LAL
1
Untuk kompiler MS:
#define inc_enum(i)((decltype(i))((int)i +1))enum enumtype { one, two, three, count};for(enumtype i = one; i < count; i = inc_enum(i)){
dostuff(i);}
Catatan: ini jauh lebih sedikit kode daripada jawaban iterator kustom templatized sederhana.
Anda bisa membuatnya bekerja dengan GCC dengan menggunakan typeofalih-alih decltype, tetapi saya tidak memiliki kompiler yang berguna saat ini untuk memastikan kompilasi.
Ini ditulis ~ 5 tahun setelah decltypemenjadi standar C ++, jadi sebaiknya Anda tidak merekomendasikan yang sudah ketinggalan zaman typeofdari GCC kuno. Menangani GCC baru- decltypebaru ini saja. Ada masalah lain: gips C-style tidak disarankan, & makro lebih buruk. Fitur C ++ yang tepat dapat memberikan fungsionalitas generik yang sama. Ini akan lebih baik ditulis ulang untuk menggunakan static_cast& fungsi template: template <typename T> auto inc_enum(T const t) { return static_cast<T>(static cast<int>(t) + 1); }. Dan gips tidak diperlukan untuk non- enum class. Atau, operator dapat kelebihan beban per enumjenis (TIL)
underscore_d
1
typedefenum{
first =2,
second =6,
third =17}MyEnum;staticconstint enumItems[]={
first,
second,
third
}staticconstintEnumLength=sizeof(enumItems)/sizeof(int);for(int i =0; i <EnumLength; i++){//Do something with enumItems[i]}
Solusi ini akan membuat variabel statis yang tidak perlu dalam memori sementara tujuan enum adalah hanya untuk membuat 'topeng' ke konstanta yang digarisbawahi
TheArquitect
Kecuali diubah menjadiconstexpr static const int enumItems[]
Mohammad Kanan
0
C ++ tidak memiliki introspeksi, jadi Anda tidak dapat menentukan hal seperti ini saat dijalankan.
Bisakah Anda menjelaskan kepada saya mengapa "introspeksi" diperlukan untuk beralih pada enum?
Jonathan Mee
Mungkin istilahnya Refleksi ?
kͩeͣmͮpͥ ͩ
2
Saya mencoba mengatakan 2 hal: 1) Per banyak jawaban lain, C ++ dapat menyelesaikannya, jadi jika Anda ingin mengatakannya tidak bisa, tautan atau klarifikasi lebih lanjut diperlukan. 2) Dalam bentuk saat ini, ini yang terbaik adalah komentar, tentu bukan jawaban.
Jonathan Mee
Turunkan jawaban saya - saya pikir Anda lebih dari membenarkannya
kͩeͣmͮpͥ ͩ
1
Saya akan menjejalkan lagi dalam 2 komentar: 1) Saya tidak downvote karena saya menemukan bahwa menerima downvote mendemotivasi partisipasi situs, saya menemukan kontraproduktif 2) Saya masih tidak mengerti apa yang Anda katakan tetapi kedengarannya seperti Anda memahami sesuatu yang saya tidak tahu dalam hal ini saya lebih suka Anda menjelaskan daripada menghapus jawaban yang downvoted.
Jonathan Mee
0
Jika Anda tahu bahwa nilai enum berurutan, misalnya Qt: Key enum, Anda bisa:
int
mungkin tidak cukup besar! ([C++03: 7.2/5]
)operator++
pada enum; Namun, jadi Anda bisa melakukannyafor(Enum_E e = (Enum_E)0; e < ENUM_COUNT; e++)
. Catatan Anda harus cor0
untukEnum_E
karena operator C ++ larang tugas pada enum.Jawaban:
Cara khasnya adalah sebagai berikut:
Harap dicatat, enum
Last
dimaksudkan untuk dilewati oleh iterasi. Dengan menggunakanLast
enum "palsu" ini , Anda tidak harus memperbarui kondisi terminating di dalam for loop ke enum "real" terakhir setiap kali Anda ingin menambahkan enum baru. Jika Anda ingin menambahkan lebih banyak enum nanti, cukup tambahkan sebelum Terakhir. Loop dalam contoh ini masih akan berfungsi.Tentu saja, ini rusak jika nilai enum ditentukan:
Ini menggambarkan bahwa enum tidak dimaksudkan untuk diulangi. Cara khas untuk menangani enum adalah menggunakannya dalam pernyataan pergantian.
Jika Anda benar-benar ingin menghitung, masukkan nilai enum dalam vektor dan ulangi. Ini akan menangani dengan baik nilai enum yang ditentukan juga.
sumber
UNKNOWN = 0
. Selain itu, saya akan menyarankan untuk hanya menjatuhkandefault
case ketika beralih nilai enum karena mungkin menyembunyikan kasus-kasus di mana penanganan nilai-nilai dilupakan sampai runtime. Sebagai gantinya, seseorang harus meng-hardcode semua nilai dan menggunakanUNKNOWN
bidang untuk mendeteksi ketidaksesuaian.sumber
static const Type All[3];
dan kemudian saya bisa untuk menginisialisasi dalam sumber:const MyEnum::Type MyEnum::All[3] = { a, b, c };
Sebelum melakukan itu, saya mendapatkanError in range-based for...
kesalahan menjengkelkan (karena array memiliki ukuran yang tidak diketahui). Menemukan ini berkat jawaban terkaitJika enum Anda mulai dengan 0 dan kenaikan selalu 1.
Jika tidak, saya kira satu-satunya sebabnya adalah membuat sesuatu seperti
tambahkan item, dan gunakan iterators normal ....
sumber
Dengan c ++ 11, sebenarnya ada alternatif: menulis iterator kustom templatized sederhana.
mari kita asumsikan enum Anda
Kode generik ini akan melakukan triknya, cukup efisien - tempatkan di header generik, itu akan membantu Anda untuk setiap enum yang mungkin perlu Anda ulangi:
Anda harus mengkhususkannya
Dan kemudian Anda bisa beralih menggunakan range-for
Asumsi bahwa Anda tidak memiliki celah di enum Anda masih benar; tidak ada asumsi pada jumlah bit yang sebenarnya diperlukan untuk menyimpan nilai enum (terima kasih kepada std :: underlying_type)
sumber
std::vector
tidak generik karenastd::vector<foo>
terikatfoo
.typedef Iterator<color, color::green, color::red> colorIterator;
Pastikan Anda memahami cara kerja Instansiasi template.foo operator*() { ...
seharusnyaC operator*() { ...
.terlalu rumit solusi ini, saya suka itu:
sumber
for (NodePosition pos : NodePositionVector)
sintaks? Sejauh yang saya tahu ini adalah sintaks Java, dan Anda akan memerlukan iterator di C ++ untuk melakukan sesuatu yang setara.auto
, jadi Anda tidak harus mendeklarasikan jenis elemen secara eksplisit, kecuali jika Anda (A) perlu menggunakan operator konversi atau (B) tidak sukaauto
karena suatu alasan . Sebagian besarfor
pengguna rentang menggunakanauto
AFAICTSaya sering melakukannya seperti itu
atau jika tidak berturut-turut, tetapi dengan langkah reguler (mis. bendera bit)
sumber
Anda tidak bisa dengan enum. Mungkin enum bukan yang paling cocok untuk situasi Anda.
Sebuah konvensi umum adalah untuk memberi nama nilai enum terakhir seperti MAX dan menggunakannya untuk mengontrol loop menggunakan int.
sumber
Sesuatu yang belum tercakup dalam jawaban lain = jika Anda menggunakan enums C ++ 11 yang diketik dengan kuat, Anda tidak dapat menggunakan
++
atau menggunakannya+ int
. Dalam hal ini, sedikit solusi berantakan diperlukan:sumber
Anda dapat mencoba dan mendefinisikan makro berikut:
Sekarang Anda dapat menggunakannya:
Ini dapat digunakan untuk beralih mundur dan maju melalui unsigned, integer, enums dan chars:
Meskipun definisi canggung itu dioptimalkan dengan sangat baik. Saya melihat disassembler di VC ++. Kode ini sangat efisien. Jangan menunda tetapi ketiganya untuk pernyataan: kompiler hanya akan menghasilkan satu loop setelah optimasi! Anda bahkan dapat mendefinisikan loop tertutup:
Anda jelas tidak dapat mengulangi melalui tipe yang disebutkan dengan kesenjangan.
sumber
_A1
bukan nama yang diizinkan, ini adalah garis bawah utama dengan huruf kapital berikut.Anda juga dapat membebani operator kenaikan / penurunan untuk tipe enumerasi Anda.
sumber
Dengan asumsi bahwa enum diberi nomor secara berurutan adalah rawan kesalahan. Selain itu, Anda mungkin ingin beralih hanya menggunakan enumerator terpilih. Jika bagian itu kecil, mengulanginya secara eksplisit mungkin merupakan pilihan yang elegan:
sumber
Jika Anda tidak ingin mencemari Anda enum dengan item COUNT akhir (karena mungkin jika Anda juga menggunakan enum dalam sebuah saklar, maka kompiler akan memperingatkan Anda tentang kasus COUNT yang hilang :), Anda dapat melakukan ini:
sumber
Inilah solusi lain yang hanya berfungsi untuk enum yang berdekatan. Ini memberikan iterasi yang diharapkan, kecuali untuk keburukan dalam kenaikan, yang merupakan tempatnya, karena itulah yang rusak di C ++.
sumber
foo = Bar(foo + 1)
.SEBUAH
constexpr std::array
dapat mengulang bahkan enum non-sekuensial tanpa array yang dipakai oleh kompiler. Ini tergantung pada hal-hal seperti heuristik optimisasi kompiler dan apakah Anda mengambil alamat array.Dalam percobaan saya, saya menemukan bahwa
g++
9,1 dengan-O3
akan mengoptimalkan array di atas jika ada 2 nilai non-sekuensial atau beberapa nilai sekuensial (saya menguji hingga 6). Tetapi ini hanya berlaku jika Anda memilikiif
pernyataan. (Saya mencoba pernyataan yang membandingkan nilai integer lebih besar dari semua elemen dalam array berurutan dan itu menggarisbawahi iterasi meskipun tidak ada yang dikecualikan, tetapi ketika saya meninggalkan pernyataan if, nilai-nilai itu dimasukkan ke dalam memori.) nilai dari enum non-sekuensial dalam [satu kasus | https://godbolt.org/z/XuGtoc] . Saya menduga perilaku aneh ini adalah karena heuristik yang mendalam berkaitan dengan cache dan prediksi cabang.Berikut ini tautan ke tes iterasi sederhana di godbolt yang menunjukkan bahwa array tidak selalu dapat dipakai.
Harga dari teknik ini adalah menulis elemen enum dua kali dan menjaga kedua daftar tetap sinkron.
sumber
Dalam buku bahasa pemrograman C ++ dari Bjarne Stroustrup, Anda dapat membaca bahwa ia mengusulkan untuk membebani buku
operator++
khusus Andaenum
.enum
apakah tipe yang ditentukan pengguna dan operator kelebihan beban ada dalam bahasa untuk situasi khusus ini.Anda dapat membuat kode berikut:
kode uji: http://cpp.sh/357gb
Pikiran yang saya gunakan
enum class
. Kode berfungsi dengan baikenum
juga. Tapi saya lebih sukaenum class
karena mereka diketik dengan kuat dan dapat mencegah kita melakukan kesalahan pada waktu kompilasi.sumber
enum
. Itu bukan pertanyaan arsitektur. Saya tidak percaya bahwa pada 2013 C ++ adalah fiksi ilmiah.Untuk kompiler MS:
Catatan: ini jauh lebih sedikit kode daripada jawaban iterator kustom templatized sederhana.
Anda bisa membuatnya bekerja dengan GCC dengan menggunakan
typeof
alih-alihdecltype
, tetapi saya tidak memiliki kompiler yang berguna saat ini untuk memastikan kompilasi.sumber
decltype
menjadi standar C ++, jadi sebaiknya Anda tidak merekomendasikan yang sudah ketinggalan zamantypeof
dari GCC kuno. Menangani GCC baru-decltype
baru ini saja. Ada masalah lain: gips C-style tidak disarankan, & makro lebih buruk. Fitur C ++ yang tepat dapat memberikan fungsionalitas generik yang sama. Ini akan lebih baik ditulis ulang untuk menggunakanstatic_cast
& fungsi template:template <typename T> auto inc_enum(T const t) { return static_cast<T>(static cast<int>(t) + 1); }
. Dan gips tidak diperlukan untuk non-enum class
. Atau, operator dapat kelebihan beban perenum
jenis (TIL)sumber
constexpr static const int enumItems[]
C ++ tidak memiliki introspeksi, jadi Anda tidak dapat menentukan hal seperti ini saat dijalankan.
sumber
Jika Anda tahu bahwa nilai enum berurutan, misalnya Qt: Key enum, Anda bisa:
Ini berfungsi seperti yang diharapkan.
sumber
Buat saja array int dan loop di atas array, tetapi buat elemen terakhir katakan -1 dan gunakan untuk kondisi keluar.
Jika enum adalah:
lalu buat array:
Ini tidak rusak tidak peduli ints dalam representasi selama -1 cek tidak bertabrakan dengan salah satu elemen saja.
sumber