Ich habe eine Reihe von Aufzählungstypen in einigen Bibliotheksheaderdateien, die ich verwende, und ich möchte eine Möglichkeit haben, Aufzählungswerte in Benutzerzeichenfolgen zu konvertieren - und umgekehrt.
RTTI wird das für mich nicht tun, da die 'Benutzerzeichenfolgen' etwas besser lesbar sein müssen als die Aufzählungen.
Eine Brute-Force-Lösung wäre eine Reihe solcher Funktionen, aber ich denke, das ist ein bisschen zu C-ähnlich.
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");
}
}
Ich habe das Gefühl, dass es eine elegante Lösung mit Vorlagen gibt, aber ich kann mich noch nicht ganz darum kümmern.
UPDATE: Vielen Dank für Ihre Vorschläge. Ich hätte klarstellen müssen, dass die Aufzählungen in einem Bibliotheksheader eines Drittanbieters definiert sind, damit ich die Definition nicht ändern muss.
Mein Bauchgefühl ist es jetzt, Vorlagen zu vermeiden und so etwas zu tun:
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);
Antworten:
Wenn Sie möchten, dass die Aufzählungsnamen selbst als Zeichenfolgen verwendet werden, lesen Sie diesen Beitrag . Ansonsten a
std::map<MyEnum, char const*>
funktionieren. (Es macht keinen Sinn, Ihre String-Literale in std :: strings in der Map zu kopieren.)Für zusätzlichen syntaktischen Zucker schreiben Sie hier eine map_init-Klasse. Das Ziel ist zu erlauben
Die Funktion
template <typename T> map_init(T&)
gibt a zurückmap_init_helper<T>
.map_init_helper<T>
speichert ein T & und definiert das Trivialemap_init_helper& operator()(typename T::key_type const&, typename T::value_type const&)
. (Die Rückkehr*this
vonoperator()
ermöglicht das Verketten vonoperator()
, wieoperator<<
beistd::ostream
s)Da die Funktion und die Hilfsklasse als Vorlagen verwendet werden, können Sie sie für jede Karte oder kartenähnliche Struktur verwenden. Dh es können auch Einträge hinzugefügt werden
std::unordered_map
Wenn Sie diese Helfer nicht gerne schreiben, bietet boost :: assign sofort die gleiche Funktionalität.
quelle
Die MSalters-Lösung ist gut, wird jedoch grundsätzlich neu implementiert
boost::assign::map_list_of
. Wenn Sie Boost haben, können Sie es direkt verwenden:quelle
eee
in Ihrem Fall nur für den Typ funktioniert .error: template declaration of 'const boost::unordered::unordered_map<T, const char*> enumToString'
.Ein Formular automatisch aus einem anderen generieren.
Quelle:
Generiert:
Wenn die Enum-Werte groß sind, kann ein generiertes Formular unordered_map <> oder Vorlagen verwenden, wie von Constantin vorgeschlagen.
Quelle:
Generiert:
Beispiel:
quelle
Ich erinnere mich, dass ich dies an anderer Stelle auf StackOverflow beantwortet habe. Wiederholen Sie es hier. Grundsätzlich handelt es sich um eine Lösung, die auf verschiedenen Makros basiert und recht einfach zu verwenden ist:
Um es in Ihrem Code zu verwenden, gehen Sie einfach wie folgt vor:
quelle
Ich schlage vor, eine Mischung aus X-Makros ist die beste Lösung und die folgenden Vorlagenfunktionen:
Marcinkoziukmyopenidcom auszuleihen und zu verlängern
colour.def
quelle
Ich benutze diese Lösung, die ich unten wiedergebe:
quelle
Wenn Sie Zeichenfolgendarstellungen von
MyEnum
Variablen erhalten möchten, werden diese von Vorlagen nicht abgeschnitten. Die Vorlage kann auf Integralwerte spezialisiert werden, die zur Kompilierungszeit bekannt sind.Wenn Sie dies jedoch möchten, versuchen Sie Folgendes:
Dies ist ausführlich, fängt jedoch Fehler wie den von Ihnen in Frage gestellten ab - Ihr Fehler
case VAL1
wird dupliziert.quelle
Ich habe mehr Zeit damit verbracht, dieses Thema zu erforschen, als ich zugeben möchte. Glücklicherweise gibt es großartige Open Source-Lösungen in freier Wildbahn.
Dies sind zwei großartige Ansätze, auch wenn sie (noch) nicht bekannt genug sind:
weise_enum
Bessere Aufzählungen
quelle
Ich wäre versucht, eine Karte m zu haben - und diese in die Aufzählung einzubetten.
Setup mit m [MyEnum.VAL1] = "Wert 1";
und alles ist erledigt.
quelle
Ich habe diese Funktionalität mehrmals zum Debuggen / Analysieren von Code von anderen benötigt. Zu diesem Zweck habe ich ein Perl-Skript geschrieben, das eine Klasse mit mehreren überladenen
toString
Methoden generiert . JedetoString
Methode nimmt einEnum
als Argument und gibt zurückconst char*
.Natürlich analysiert das Skript C ++ nicht nach Aufzählungen selbst, sondern verwendet ctags zum Generieren der Symboltabelle.
Das Perl-Skript finden Sie hier: http://heinitz-it.de/download/enum2string/enum2string.pl.html
quelle
Ihre Antworten haben mich dazu inspiriert, selbst einige Makros zu schreiben. Meine Anforderungen waren folgende:
Schreiben Sie jeden Wert der Aufzählung nur einmal, sodass keine doppelten Listen gepflegt werden müssen
Bewahren Sie die Aufzählungswerte nicht in einer separaten Datei auf, die später # eingeschlossen wird, damit ich sie schreiben kann, wo immer ich will
Ersetzen Sie nicht die Aufzählung selbst, ich möchte immer noch den Aufzählungstyp definieren, aber zusätzlich möchte ich in der Lage sein, jeden Aufzählungsnamen der entsprechenden Zeichenfolge zuzuordnen (um den Legacy-Code nicht zu beeinflussen).
Die Suche sollte schnell sein, also vorzugsweise kein Switch-Case für diese riesigen Enums
Dieser Code erstellt eine klassische Aufzählung mit einigen Werten. Außerdem wird als std :: map erstellt, die jeden Aufzählungswert seinem Namen zuordnet (dh map [E_SUNDAY] = "E_SUNDAY" usw.)
Ok, hier ist jetzt der Code:
EnumUtilsImpl.h :
EnumUtils.h // Dies ist die Datei, die Sie einschließen möchten, wenn Sie dieses Zeug ausführen müssen. Sie werden die Makros daraus verwenden:
MyProjectCodeFile.h // Dies ist ein Beispiel für die Verwendung zum Erstellen einer benutzerdefinierten Aufzählung:
Prost.
quelle
Hier ist ein Versuch, << und >> Stream-Operatoren automatisch mit einem einzeiligen Makrobefehl auf enum zu bringen ...
Definitionen:
Verwendung:
Ich bin mir nicht sicher über die Einschränkungen dieses Schemas ... Kommentare sind willkommen!
quelle
in der Kopfzeile:
in der CPP-Datei:
Vorsichtsmaßnahme: Behandeln Sie keinen schlechten Array-Index. :) Sie können jedoch problemlos eine Funktion hinzufügen, um die Aufzählung zu überprüfen, bevor Sie die Zeichenfolge aus dem Array abrufen.
quelle
Ich wollte diese mögliche elegante Lösung nur mit Makros zeigen. Dies löst das Problem nicht, aber ich denke, es ist ein guter Weg, um über das Problem nachzudenken.
---- BEARBEITEN ----
Nach einigen Internetrecherchen und eigenen Experimenten kam ich zu folgender Lösung:
Ich wollte es nur posten, vielleicht könnte jemand diese Lösung nützlich finden. Es sind keine Vorlagenklassen erforderlich, kein C ++ 11 und kein Boost erforderlich, sodass dies auch für einfaches C verwendet werden kann.
---- EDIT2 ----
Die Informationstabelle kann bei Verwendung von mehr als 2 Aufzählungen zu Problemen führen (Compilerproblem). Die folgende Problemumgehung hat funktioniert:
quelle
Oben ist meine einfache Lösung. Ein Vorteil davon ist die 'NUM', die die Größe des Nachrichtenarrays steuert und auch den Zugriff außerhalb der Grenzen verhindert (wenn Sie es mit Bedacht verwenden).
Sie können auch eine Funktion definieren, um die Zeichenfolge abzurufen:
Nach meiner Lösung fand ich dann die folgende ziemlich interessant. Es löste im Allgemeinen das Synchronisationsproblem des obigen.
Folien hier: http://www.slideshare.net/arunksaha/touchless-enum-tostring-28684724
Code hier: https://github.com/arunksaha/enum_to_string
quelle
Ich weiß, dass ich zu spät zum Feiern bin, aber für alle anderen, die diese Seite besuchen, könnten Sie es versuchen, es ist einfacher als alles dort und macht mehr Sinn:
quelle
Ich hatte kürzlich das gleiche Problem mit einer Herstellerbibliothek (Fincad). Glücklicherweise hat der Anbieter eine XML-Dokumentation für alle Aufzählungen bereitgestellt. Am Ende habe ich für jeden Aufzählungstyp eine Karte erstellt und für jede Aufzählung eine Suchfunktion bereitgestellt. Mit dieser Technik können Sie auch eine Suche außerhalb des Bereichs der Aufzählung abfangen.
Ich bin mir sicher, dass swig etwas Ähnliches für Sie tun könnte, aber ich bin froh, die in Ruby geschriebenen Dienstprogramme zur Codegenerierung bereitstellen zu können.
Hier ist ein Beispiel des Codes:
Scheint, als ob Sie den anderen Weg gehen möchten (Aufzählung zu Zeichenfolge, anstatt Zeichenfolge zu Aufzählung), aber dies sollte trivial sein, um es umzukehren.
-Weiß
quelle
Überprüfen Sie, ob die folgende Syntax zu Ihnen passt:
Wenn dies der Fall ist, sollten Sie diesen Artikel lesen :
http://www.gamedev.net/reference/snippets/features/cppstringizing/
quelle
Dieses richtige alte Durcheinander ist meine Anstrengung, basierend auf Kleinigkeiten von SO. Das for_each müsste erweitert werden, um mehr als 20 Aufzählungswerte zu unterstützen. Getestet auf Visual Studio 2019, Clang und GCC. c ++ 11
Dies erzeugt den folgenden Code
So schade, dass man mit dem Präprozessor springen muss, um dies in einer der am häufigsten verwendeten Programmiersprachen der Welt zu tun ...
quelle