Mam kilka typów wyliczeń w niektórych plikach nagłówkowych bibliotek, których używam, i chcę mieć sposób konwertowania wartości wyliczenia na ciągi użytkownika - i odwrotnie.
RTTI nie zrobi tego za mnie, ponieważ „ciągi użytkowników” muszą być nieco bardziej czytelne niż wyliczenia.
Rozwiązaniem brutalnej siły byłoby kilka takich funkcji, ale wydaje mi się, że jest to trochę zbyt podobne do 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");
}
}
Mam przeczucie, że istnieje eleganckie rozwiązanie wykorzystujące szablony, ale nie mogę jeszcze tego ogarnąć.
AKTUALIZACJA: Dzięki za sugestie - powinienem był wyjaśnić, że wyliczenia są zdefiniowane w nagłówku biblioteki innej firmy, więc nie chcę zmieniać ich definicji.
Mam teraz przeczucie, że unikam szablonów i robię coś takiego:
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);
Odpowiedzi:
Jeśli chcesz, aby wyliczenia same się nazywały jako ciągi, zobacz ten post . W przeciwnym razie a
std::map<MyEnum, char const*>
będzie dobrze działać. (Nie ma sensu kopiowanie literałów ciągów do std :: strings na mapie)Aby uzyskać dodatkowy cukier składniowy, oto jak napisać klasę map_init. Celem jest pozwolenie
Funkcja
template <typename T> map_init(T&)
zwracamap_init_helper<T>
.map_init_helper<T>
przechowuje T & i definiuje trywialnemap_init_helper& operator()(typename T::key_type const&, typename T::value_type const&)
. (Wracając*this
zoperator()
pozwala na łączenieoperator()
, jakoperator<<
nastd::ostream
s)Ponieważ funkcja i klasa pomocnicza są oparte na szablonach, można ich użyć do dowolnej mapy lub struktury podobnej do mapy. To znaczy może również dodawać wpisy do
std::unordered_map
Jeśli nie lubisz pisać tych pomocników, boost :: assign oferuje te same funkcje po wyjęciu z pudełka.
źródło
Rozwiązanie MSalters jest dobre, ale w zasadzie ponownie wdraża
boost::assign::map_list_of
. Jeśli masz doładowanie, możesz go użyć bezpośrednio:źródło
eee
w Twoim przypadku.error: template declaration of 'const boost::unordered::unordered_map<T, const char*> enumToString'
.Automatycznie generuj jeden formularz z innego.
Źródło:
Wygenerowano:
Jeśli wartości wyliczenia są duże, wygenerowany formularz może używać unordered_map <> lub szablonów, zgodnie z sugestią Constantina.
Źródło:
Wygenerowano:
Przykład:
źródło
Pamiętam, że odpowiedziałem na to gdzie indziej w StackOverflow. Powtarzam to tutaj. Zasadniczo jest to rozwiązanie oparte na wariadycznych makrach i jest dość łatwe w użyciu:
Aby użyć go w swoim kodzie, po prostu wykonaj:
źródło
Proponuję połączenie X-makr to najlepsze rozwiązanie i następujące funkcje szablonu:
Pożyczyć od marcinkoziukmyopenidcom i rozszerzony
colour.def
źródło
Korzystam z tego rozwiązania, które poniżej przedstawiam:
źródło
Jeśli chcesz uzyskać reprezentacje łańcuchowe
MyEnum
zmiennych , szablony tego nie wycinają. Szablon może być wyspecjalizowany w wartościach całkowitych znanych w czasie kompilacji.Jeśli jednak tego chcesz, spróbuj:
To jest rozwlekłe, ale wykryje błędy takie jak ten, który popełniłeś - Twój
case VAL1
jest duplikatem.źródło
Spędziłem więcej czasu na badaniu tego tematu, do którego chciałbym się przyznać. Na szczęście na wolności istnieją świetne rozwiązania open source.
To są dwa świetne podejścia, nawet jeśli nie są wystarczająco (jeszcze) znane,
wise_enum
Better Enums
źródło
Chciałbym mieć mapę m - i osadzić ją w enum.
konfiguracja z m [MyEnum.VAL1] = "Wartość 1";
i wszystko gotowe.
źródło
Kilkakrotnie potrzebowałem tej funkcji do debugowania / analizowania kodu od innych. W tym celu napisałem skrypt Perla, który generuje klasę z kilkoma przeciążonymi
toString
metodami. KażdatoString
metoda przyjmujeEnum
argument jako argument i zwracaconst char*
.Oczywiście skrypt nie analizuje samego C ++ pod kątem wyliczeń, ale używa ctags do generowania tablicy symboli.
Skrypt Perla jest tutaj: http://heinitz-it.de/download/enum2string/enum2string.pl.html
źródło
Twoje odpowiedzi zainspirowały mnie do samodzielnego napisania makr. Moje wymagania były następujące:
zapisuj każdą wartość wyliczenia tylko raz, więc nie ma podwójnych list do obsługi
nie przechowuj wartości wyliczenia w osobnym pliku, który jest później # uwzględniony, więc mogę zapisać go w dowolnym miejscu
nie zastępuj samego wyliczenia, nadal chcę mieć zdefiniowany typ wyliczenia, ale oprócz tego chcę mieć możliwość mapowania każdej nazwy wyliczenia na odpowiedni ciąg (aby nie wpływać na starszy kod)
wyszukiwanie powinno być szybkie, więc najlepiej bez przełączników dla tych ogromnych wyliczeń
Ten kod tworzy klasyczne wyliczenie z pewnymi wartościami. Ponadto tworzy jako std :: map, które mapuje każdą wartość wyliczenia na jej nazwę (tj. Map [E_SUNDAY] = "E_SUNDAY" itp.)
Ok, oto kod teraz:
EnumUtilsImpl.h :
EnumUtils.h // to jest plik, który chcesz dołączyć za każdym razem, gdy będziesz musiał to zrobić, użyjesz z niego makr:
MyProjectCodeFile.h // to jest przykład tego, jak używać go do tworzenia niestandardowego wyliczenia:
Twoje zdrowie.
źródło
Oto próba automatycznego uzyskania operatorów strumieni << i >> na wyliczeniu za pomocą makra z jednym wierszem ...
Definicje:
Stosowanie:
Nie jestem pewien co do ograniczeń tego schematu ... komentarze są mile widziane!
źródło
w nagłówku:
w pliku .cpp:
Uwaga: nie obsługuj złego indeksu tablicy. :) Ale możesz łatwo dodać funkcję, która zweryfikuje wyliczenie przed pobraniem ciągu z tablicy.
źródło
Chciałem tylko pokazać to możliwe eleganckie rozwiązanie za pomocą makr. To nie rozwiązuje problemu, ale myślę, że jest to dobry sposób na ponowne przemyślenie problemu.
---- EDYTOWAĆ ----
Po przeszukiwaniu internetu i własnych doświadczeniach doszedłem do następującego rozwiązania:
Chciałem tylko opublikować, może ktoś mógłby uznać to rozwiązanie za przydatne. Nie ma potrzeby stosowania klas szablonów, nie ma potrzeby stosowania języka C ++ 11 ani wzmocnienia, więc można go również użyć w prostym C.
---- EDIT2 ----
tabela informacji może powodować pewne problemy przy użyciu więcej niż 2 wyliczeń (problem kompilatora). Następujące obejście zadziałało:
źródło
Powyżej jest moje proste rozwiązanie. Jedną z jego zalet jest „NUM”, który kontroluje rozmiar tablicy wiadomości, a także zapobiega dostępowi poza granicami (jeśli używasz go mądrze).
Możesz również zdefiniować funkcję, aby uzyskać ciąg:
W nawiązaniu do mojego rozwiązania, następne okazało się całkiem interesujące. Ogólnie rozwiązał problem synchronizacji powyższego.
Slajdy tutaj: http://www.slideshare.net/arunksaha/touchless-enum-tostring-28684724
Kod tutaj: https://github.com/arunksaha/enum_to_string
źródło
Wiem, że spóźniłem się na imprezę, ale dla każdego, kto odwiedza tę stronę, możesz spróbować, jest to łatwiejsze niż wszystko, co tam jest i ma więcej sensu:
źródło
Niedawno miałem ten sam problem z biblioteką dostawców (Fincad). Na szczęście dostawca dostarczył dokumentację XML dla wszystkich wyliczeń. Skończyło się na wygenerowaniu mapy dla każdego typu wyliczenia i udostępnieniu funkcji wyszukiwania dla każdego wyliczenia. Ta technika umożliwia również przechwycenie wyszukiwania poza zakresem wyliczenia.
Jestem pewien, że swig mógłby zrobić dla ciebie coś podobnego, ale z przyjemnością dostarczę narzędzia do generowania kodu, które są napisane w języku ruby.
Oto przykład kodu:
Wygląda na to, że chcesz przejść w drugą stronę (wyliczenie do łańcucha zamiast ciągu do wyliczenia), ale odwrócenie tego powinno być trywialne.
-Odrobina
źródło
Sprawdź, czy odpowiada Ci następująca składnia:
Jeśli tak, możesz zapoznać się z tym artykułem:
http://www.gamedev.net/reference/snippets/features/cppstringizing/
źródło
ten stary bałagan to mój wysiłek oparty na bitach i fragmentach z SO. Element for_each musiałby zostać rozwinięty, aby obsługiwał więcej niż 20 wartości wyliczeniowych. Przetestowałem to na Visual Studio 2019, Clang i GCC. c ++ 11
który tworzy następujący kod
Jaka szkoda, że obręcze, które musisz przeskoczyć z preprocesorem, aby to zrobić w jednym z najczęściej używanych języków programowania na świecie ...
źródło
Używając wyznaczonych inicjatorów tablicy, tablica ciągów jest niezależna od kolejności elementów w wyliczeniu:
źródło