Saya memiliki banyak jenis enum di beberapa file header perpustakaan yang saya gunakan, dan saya ingin memiliki cara untuk mengonversi nilai enum menjadi string pengguna - dan sebaliknya.
RTTI tidak akan melakukannya untuk saya, karena 'string pengguna' harus sedikit lebih mudah dibaca daripada enumerasi.
Solusi brute force akan menjadi sekumpulan fungsi seperti ini, tapi saya merasa itu agak terlalu mirip C.
enum MyEnum {VAL1, VAL2,VAL3};
String getStringFromEnum(MyEnum e)
{
switch e
{
case VAL1: return "Value 1";
case VAL2: return "Value 2";
case VAL1: return "Value 3";
default: throw Exception("Bad MyEnum");
}
}
Saya memiliki firasat bahwa ada solusi elegan menggunakan templat, tetapi saya belum bisa sepenuhnya memahaminya.
PEMBARUAN: Terima kasih atas saran - Saya seharusnya menjelaskan bahwa enum didefinisikan di tajuk perpustakaan pihak ketiga, jadi saya tidak ingin mengubah definisi mereka.
Perasaan saya sekarang adalah menghindari template dan melakukan sesuatu seperti ini:
char * MyGetValue(int v, char *tmp); // implementation is trivial
#define ENUM_MAP(type, strings) char * getStringValue(const type &T) \
{ \
return MyGetValue((int)T, strings); \
}
; enum eee {AA,BB,CC}; - exists in library header file
; enum fff {DD,GG,HH};
ENUM_MAP(eee,"AA|BB|CC")
ENUM_MAP(fff,"DD|GG|HH")
// To use...
eee e;
fff f;
std::cout<< getStringValue(e);
std::cout<< getStringValue(f);
Jawaban:
Jika Anda ingin nama enum itu sendiri sebagai string, lihat posting ini . Jika tidak, a
std::map<MyEnum, char const*>
akan bekerja dengan baik. (Tidak ada gunanya menyalin literal string Anda ke std :: string di peta)Untuk tambahan gula sintaksis, berikut cara menulis kelas map_init. Tujuannya adalah untuk memungkinkan
Fungsi
template <typename T> map_init(T&)
mengembalikan amap_init_helper<T>
.map_init_helper<T>
menyimpan T &, dan mendefinisikan hal sepelemap_init_helper& operator()(typename T::key_type const&, typename T::value_type const&)
. (Kembali*this
darioperator()
memungkinkan perangkaianoperator()
, sepertioperator<<
padastd::ostream
s)Karena fungsi dan kelas helper memiliki template, Anda dapat menggunakannya untuk peta apa pun, atau struktur seperti peta. Yaitu dapat juga menambahkan entri ke
std::unordered_map
Jika Anda tidak suka menulis pembantu ini, boost :: assign menawarkan fungsionalitas yang sama di luar kotak.
sumber
Solusi MSalters adalah solusi yang bagus tetapi pada dasarnya diimplementasikan kembali
boost::assign::map_list_of
. Jika Anda memiliki dorongan, Anda dapat menggunakannya secara langsung:sumber
eee
dalam kasus Anda.error: template declaration of 'const boost::unordered::unordered_map<T, const char*> enumToString'
.Buat satu formulir secara otomatis dari yang lain.
Sumber:
Dihasilkan:
Jika nilai enum besar maka formulir yang dihasilkan dapat menggunakan unordered_map <> atau template seperti yang disarankan oleh Constantin.
Sumber:
Dihasilkan:
Contoh:
sumber
Saya ingat pernah menjawab ini di tempat lain di StackOverflow. Ulangi di sini. Pada dasarnya ini adalah solusi berdasarkan makro variadic, dan cukup mudah digunakan:
Untuk menggunakannya dalam kode Anda, cukup lakukan:
sumber
Saya menyarankan perpaduan penggunaan X-macro adalah solusi terbaik dan fungsi template berikut:
Untuk meminjam marcinkoziukmyopenidcom dan diperpanjang
colour.def
sumber
Saya menggunakan solusi ini yang saya reproduksi di bawah ini:
sumber
Jika Anda ingin mendapatkan representasi string dari
MyEnum
variabel , maka template tidak akan memotongnya. Template dapat dikhususkan pada nilai integral yang diketahui pada waktu kompilasi.Namun, jika itu yang Anda inginkan, cobalah:
Ini bertele-tele, tetapi akan menangkap kesalahan seperti yang Anda buat yang dimaksud - Anda
case VAL1
digandakan.sumber
Saya telah menghabiskan lebih banyak waktu untuk meneliti topik ini yang ingin saya akui. Untungnya ada solusi sumber terbuka yang bagus di alam liar.
Ini adalah dua pendekatan hebat, meskipun belum cukup dikenal (belum),
bijaksana_enum
Enum yang Lebih Baik
sumber
Saya akan tergoda untuk memiliki peta m - dan menyematkannya ke enum.
setup dengan m [MyEnum.VAL1] = "Nilai 1";
dan semuanya selesai.
sumber
Saya memerlukan fungsi ini beberapa kali untuk men-debug / menganalisis kode dari orang lain. Untuk ini, saya telah menulis skrip Perl yang menghasilkan kelas dengan beberapa
toString
metode kelebihan beban . SetiaptoString
metode mengambilEnum
sebuah argumen dan mengembalikanconst char*
.Tentu saja, skrip tidak mengurai C ++ untuk enum itu sendiri, tetapi menggunakan ctag untuk membuat tabel simbol.
Skrip Perl ada di sini: http://heinitz-it.de/download/enum2string/enum2string.pl.html
sumber
Jawaban Anda menginspirasi saya untuk menulis beberapa makro sendiri. Persyaratan saya adalah sebagai berikut:
hanya menulis setiap nilai enum satu kali, jadi tidak ada daftar ganda yang harus dipertahankan
jangan menyimpan nilai enum di file terpisah yang #included, jadi saya bisa menuliskannya di mana pun saya mau
jangan mengganti enum itu sendiri, saya masih ingin memiliki tipe enum yang ditentukan, tetapi selain itu saya ingin dapat memetakan setiap nama enum ke string yang sesuai (untuk tidak memengaruhi kode lama)
pencarian harus cepat, jadi sebaiknya tidak ada switch-case, untuk enum besar itu
Kode ini membuat enum klasik dengan beberapa nilai. Selain itu, ia membuat sebagai std :: map yang memetakan setiap nilai enum ke namanya (yaitu peta [E_SUNDAY] = "E_SUNDAY", dll.)
Oke, ini kodenya sekarang:
EnumUtilsImpl.h :
EnumUtils.h // ini adalah file yang ingin Anda sertakan kapan pun Anda perlu melakukan hal ini, Anda akan menggunakan makro darinya:
MyProjectCodeFile.h // ini adalah contoh cara menggunakannya untuk membuat enum kustom:
Bersulang.
sumber
Berikut ini adalah upaya untuk mendapatkan << dan >> operator streaming pada enum secara otomatis dengan hanya perintah makro satu baris ...
Definisi:
Pemakaian:
Tidak yakin tentang batasan skema ini ... komentar dipersilakan!
sumber
di header:
di file .cpp:
Peringatan: Jangan menangani indeks array yang buruk. :) Tetapi Anda dapat dengan mudah menambahkan fungsi untuk memverifikasi enum sebelum mendapatkan string dari array.
sumber
Saya hanya ingin menunjukkan kemungkinan solusi elegan ini menggunakan makro. Ini tidak menyelesaikan masalah, tetapi menurut saya ini adalah cara yang baik untuk meninjau kembali masalah tersebut.
---- EDIT ----
Setelah beberapa penelitian internet dan beberapa percobaan sendiri, saya sampai pada solusi berikut:
Saya hanya ingin mempostingnya mungkin seseorang dapat menemukan solusi ini berguna. Tidak perlu kelas template, tidak perlu c ++ 11 dan tidak perlu boost sehingga ini juga bisa digunakan untuk C.
---- EDIT2 ----
tabel informasi dapat menghasilkan beberapa masalah jika menggunakan lebih dari 2 enum (masalah penyusun). Solusi berikut berhasil:
sumber
Di atas adalah solusi sederhana saya. Salah satu keuntungannya adalah 'NUM' yang mengontrol ukuran array pesan, juga mencegah akses di luar batas (jika Anda menggunakannya dengan bijak).
Anda juga dapat menentukan fungsi untuk mendapatkan string:
Selanjutnya solusi saya, saya kemudian menemukan yang berikut ini cukup menarik. Ini biasanya memecahkan masalah sinkronisasi di atas.
Slide di sini: http://www.slideshare.net/arunksaha/touchless-enum-tostring-28684724
Kode di sini: https://github.com/arunksaha/enum_to_string
sumber
Saya tahu saya terlambat ke pesta, tetapi untuk semua orang yang datang mengunjungi halaman ini, Anda dapat mencoba ini, ini lebih mudah daripada semua yang ada di sana dan lebih masuk akal:
sumber
Saya baru-baru ini mengalami masalah yang sama dengan pustaka vendor (Fincad). Untungnya, vendor menyediakan doucumentation xml untuk semua enum. Saya akhirnya menghasilkan peta untuk setiap jenis enum dan menyediakan fungsi pencarian untuk setiap enum. Teknik ini juga memungkinkan Anda mencegat pencarian di luar rentang enum.
Saya yakin swig dapat melakukan hal serupa untuk Anda, tetapi saya dengan senang hati memberikan utilitas pembuatan kode yang ditulis dalam ruby.
Berikut ini contoh kodenya:
Sepertinya Anda ingin pergi ke arah lain (enum ke string, bukan string ke enum), tapi ini harus mudah untuk dibalik.
-Sedikit
sumber
Lihat apakah sintaks berikut cocok untuk Anda:
Jika ya, Anda mungkin ingin membaca artikel ini:
http://www.gamedev.net/reference/snippets/features/cppstringizing/
sumber
kekacauan lama yang tepat ini adalah usaha saya berdasarkan potongan-potongan dari SO. For_each harus diperluas untuk mendukung lebih dari 20 nilai enum. Mengujinya di visual studio 2019, clang dan gcc. c ++ 11
yang menghasilkan kode berikut
Sayang sekali rintangan yang harus Anda lewati dengan preprocessor untuk melakukan ini di salah satu bahasa pemrograman yang paling banyak digunakan di dunia ...
sumber
Dengan menggunakan penginisialisasi larik yang ditentukan, larik string Anda tidak bergantung pada urutan elemen dalam enum:
sumber