Angenommen, wir haben einige benannte Aufzählungen:
enum MyEnum {
FOO,
BAR = 0x50
};
Was ich gegoogelt habe, ist ein Skript (jede Sprache), das alle Header in meinem Projekt scannt und einen Header mit einer Funktion pro Aufzählung generiert.
char* enum_to_string(MyEnum t);
Und eine Implementierung mit so etwas:
char* enum_to_string(MyEnum t){
switch(t){
case FOO:
return "FOO";
case BAR:
return "BAR";
default:
return "INVALID ENUM";
}
}
Das Gotcha besteht wirklich aus typisierten Aufzählungen und unbenannten Aufzählungen im C-Stil. Weiß jemand etwas dafür?
BEARBEITEN: Die Lösung sollte meine Quelle mit Ausnahme der generierten Funktionen nicht ändern. Die Aufzählungen befinden sich in einer API, daher ist die Verwendung der bisher vorgeschlagenen Lösungen keine Option.
Antworten:
Vielleicht möchten Sie GCCXML ausprobieren .
Wenn Sie GCCXML in Ihrem Beispielcode ausführen, erhalten Sie Folgendes:
Sie können jede Sprache verwenden, die Sie bevorzugen, um die Tags Enumeration und EnumValue herauszuziehen und den gewünschten Code zu generieren.
quelle
X-Makros sind die beste Lösung. Beispiel:
colours.def:
Normalerweise bevorzuge ich jedoch die folgende Methode, damit die Zeichenfolge etwas angepasst werden kann.
quelle
#define X(a, b) #b
. Dies ist nur erforderlich, wenn die Definition so aussiehtX(Red, red)
und nicht die in der Antwort gezeigte DefinitionX(Red, "red")
@hydroo: Ohne die zusätzliche Datei:
quelle
MetaSyntacticVariableNames[]
um Teil einer Klassendeklaration zu sein, indemstatic const char* getNameByEnum(MetaSyntacticVariable e) { /*code to return the static string*/ }
Ich neige dazu, ein C-Array mit den Namen in derselben Reihenfolge und Position wie die Enum-Werte zu erstellen.
z.B.
Dann können Sie das Array an Stellen verwenden, an denen Sie einen für Menschen lesbaren Wert wünschen, z
Sie können ein wenig mit dem Stringisierungsoperator experimentieren (siehe # in Ihrer Präprozessorreferenz), der unter bestimmten Umständen das tut, was Sie wollen - z.
druckt "rot" auf stdout. Leider funktioniert es für eine Variable nicht (da der Variablenname ausgedruckt wird)
quelle
Ich habe ein unglaublich einfach zu verwendendes Makro, das dies völlig trocken macht. Es beinhaltet verschiedene Makros und einige einfache Parsing-Magie. Hier geht:
Um dies in Ihrem Code zu verwenden, gehen Sie einfach wie folgt vor:
quelle
QT kann das von (dank des Meta-Objekt-Compilers) ziehen:
Quelle
quelle
Dies kann in C ++ 11 erfolgen
quelle
Ich habe dieses Rad heute neu erfunden und dachte, ich würde es teilen.
Diese Implementierung ist nicht erforderlich Änderungen an den Code, der die Konstanten definiert, die Aufzählungen oder sein kann ,
#define
s oder irgendetwas anderes , dass zufällt auf eine ganze Zahl - in meinem Fall hatte ich Symbole in Bezug auf den anderen Symbolen definiert. Es funktioniert auch gut mit spärlichen Werten. Es sind sogar mehrere Namen für denselben Wert zulässig, wobei immer der erste zurückgegeben wird. Der einzige Nachteil ist, dass Sie eine Tabelle mit den Konstanten erstellen müssen, die möglicherweise veraltet sind, wenn beispielsweise neue hinzugefügt werden.Ein Beispiel, wie Sie es verwenden würden:
Die
IdToName
Funktion beruht aufstd::lower_bound
schnellen Suchvorgängen, bei denen die Tabelle sortiert werden muss. Wenn die ersten beiden Einträge in der Tabelle nicht in der richtigen Reihenfolge sind, wird sie von der Funktion automatisch sortiert.Bearbeiten: Ein Kommentar ließ mich über eine andere Möglichkeit nachdenken, dasselbe Prinzip anzuwenden. Ein Makro vereinfacht die Generierung einer großen
switch
Anweisung.quelle
switch and case
da es einfach und leicht zu verstehen ist.Weitere Diskussion zu dieser Methode
Tricks der Präprozessor-Direktive für Neulinge
quelle
Interessant zu sehen, wie viele Möglichkeiten es gibt. Hier ist eine, die ich vor langer Zeit benutzt habe:
in der Datei myenummap.h:
in main.cpp
Es ist nicht const, aber es ist bequem.
Hier ist eine andere Möglichkeit, die C ++ 11-Funktionen verwendet. Dies ist const, erbt keinen STL-Container und ist etwas aufgeräumter:
quelle
Verwendung:
quelle
MyEnum x = MyEnum::TWO;
. Ich habe meine Bearbeitung Ihrer Klasse veröffentlicht, um dies zu unterstützen.Sumas Makrolösung ist nett. Sie müssen jedoch nicht zwei verschiedene Makros haben. C ++ enthält gerne zweimal einen Header. Lassen Sie einfach die Include-Wache weg.
Sie hätten also eine foobar.h, die nur definiert
und Sie würden es so einschließen:
enumfactory.h macht 2
#include ENUMFACTORY_ARGUMENT
s. In der ersten Runde wird ENUM wie bei Suma erweitertDECLARE_ENUM
. in der zweiten Runde funktioniert ENUM wieDEFINE_ENUM
.Sie können enumfactory.h auch mehrmals einschließen, solange Sie verschiedene # Definitionen für ENUMFACTORY_ARGUMENT übergeben
quelle
Beachten Sie, dass Ihre Konvertierungsfunktion idealerweise ein const char * zurückgeben sollte.
Wenn Sie es sich leisten können, Ihre Aufzählungen in ihre separaten Header-Dateien zu stellen, könnten Sie vielleicht so etwas mit Makros machen (oh, das wird hässlich):
Wo enum_def.h hat:
Und enum_conv.h hat:
Und schließlich hat colour.h:
Und Sie können die Konvertierungsfunktion verwenden als:
Dies ist hässlich, aber es ist die einzige Möglichkeit (auf Präprozessorebene), mit der Sie Ihre Aufzählung nur an einer einzigen Stelle in Ihrem Code definieren können. Ihr Code ist daher nicht fehleranfällig aufgrund von Änderungen an der Aufzählung. Ihre Aufzählungsdefinition und die Konvertierungsfunktion sind immer synchron. Ich wiederhole jedoch, das ist hässlich :)
quelle
Eine andere Antwort: In einigen Kontexten ist es sinnvoll, Ihre Aufzählung in einem Nicht-Code-Format wie einer CSV-, YAML- oder XML-Datei zu definieren und dann sowohl den C ++ - Aufzählungscode als auch den To-String-Code aus der Definition zu generieren. Dieser Ansatz kann in Ihrer Anwendung praktisch sein oder auch nicht, ist jedoch zu beachten.
quelle
Dies ist eine Änderung der Antwort @ user3360260. Es hat die folgenden neuen Funktionen
MyEnum fromString(const string&)
UnterstützungVerwendung:
Hier ist der Code
Beachten Sie, dass die Konvertierung in String eine schnelle Suche ist, während die Konvertierung in String eine langsame lineare Suche ist. Aber Strings sind sowieso so teuer (und die zugehörige Datei-E / A), dass ich nicht das Bedürfnis hatte, eine Bimap zu optimieren oder zu verwenden.
quelle
Hier eine One-File-Lösung (basierend auf der eleganten Antwort von @Marcin:
quelle
Ich mache das mit separaten Enum-Wrapper-Klassen nebeneinander, die mit Makros generiert werden. Es gibt mehrere Vorteile:
Der Nachteil ist natürlich, dass ich die Enum-Werte in den Formatierungsklassen duplizieren muss und kein Skript habe, um sie zu generieren. Davon abgesehen scheint es jedoch ziemlich gut zu funktionieren.
Hier ist ein Beispiel für eine Aufzählung aus meiner Codebasis ohne den gesamten Framework-Code, der die Makros und Vorlagen implementiert, aber Sie können sich vorstellen:
Die Idee ist dann, anstatt EHelpLocation zu verwenden, SEHelpLocation zu verwenden. Alles funktioniert gleich, aber Sie erhalten eine Bereichsprüfung und eine 'Format ()' - Methode für die Enum-Variable selbst. Wenn Sie einen eigenständigen Wert formatieren müssen, können Sie CEnumFormatter_EHelpLocation :: FormatEnum (...) verwenden.
Hoffe das ist hilfreich. Mir ist klar, dass dies auch nicht die ursprüngliche Frage nach einem Skript zum Generieren der anderen Klasse anspricht, aber ich hoffe, dass die Struktur jemandem hilft, der versucht, dasselbe Problem zu lösen oder ein solches Skript zu schreiben.
quelle
Es ist unveröffentlichte Software, aber es scheint, dass BOOST_ENUM von Frank Laub genau das Richtige für Sie sein könnte. Der Teil, den ich daran mag, ist, dass Sie eine Aufzählung im Rahmen einer Klasse definieren können, die die meisten makrobasierten Aufzählungen normalerweise nicht zulassen. Es befindet sich im Boost-Tresor unter: http://www.boostpro.com/vault/index.php?action=downloadfile&filename=enum_rev4.6.zip&directory=& Es hat seit 2006 keine Entwicklung mehr gesehen, daher habe ich keine wissen, wie gut es mit den neuen Boost-Versionen kompiliert. Suchen Sie unter libs / test nach einem Verwendungsbeispiel.
quelle
Dies war meine Lösung mit BOOST:
Um eine Aufzählung zu erstellen, deklarieren Sie:
Für Umbauten:
quelle
Ich möchte dies posten, falls jemand es nützlich findet.
In meinem Fall muss ich einfach eine einzelne C ++ 11-Enumeration aus einer einzelnen Datei generieren
ToString()
undFromString()
funktionieren.hpp
.Ich habe ein Python-Skript geschrieben, das die Header-Datei mit den Enum-Elementen analysiert und die Funktionen in einer neuen
.cpp
Datei generiert .Sie können dieses Skript in CMakeLists.txt mit execute_process oder als Pre-Build-Ereignis in Visual Studio hinzufügen . Die
.cpp
Datei wird automatisch generiert, ohne dass sie jedes Mal manuell aktualisiert werden muss, wenn ein neues Aufzählungselement hinzugefügt wird.generate_enum_strings.py
Beispiel:
ErrorCode.hpp
Lauf
python generate_enum_strings.py ErrorCode.hpp
Ergebnis:
ErrorCode.cpp
quelle
Die fantastische Antwort von Jasper Bekkers wird noch einfacher :
Einmal einrichten:
Dann zur Verwendung:
quelle
Sie könnten eine Reflexionsbibliothek wie Ponder verwenden . Sie registrieren die Aufzählungen und können sie dann mit der API hin und her konvertieren.
quelle
Ein Problem mit Antwort 0 besteht darin, dass die Enum-Binärwerte nicht unbedingt bei 0 beginnen und nicht unbedingt zusammenhängend sind.
Wenn ich das brauche, mache ich normalerweise:
quelle
Das folgende Ruby-Skript versucht, die Header zu analysieren, und erstellt die erforderlichen Quellen neben den ursprünglichen Headern.
Die Verwendung regulärer Ausdrücke macht diesen "Parser" sehr zerbrechlich. Möglicherweise kann er Ihre spezifischen Header nicht ordnungsgemäß verarbeiten.
Angenommen, Sie haben einen Header toto / ah, der Definitionen für die Aufzählungen MyEnum und MyEnum2 enthält. Das Skript wird Folgendes erstellen:
Robustere Lösungen wären:
quelle
Dies ist so ziemlich die einzige Möglichkeit (ein Array von Zeichenfolgen könnte auch funktionieren).
Das Problem ist, dass nach dem Kompilieren eines C-Programms nur der Binärwert der Aufzählung verwendet wird und der Name weg ist.
quelle
Hier ist ein CLI-Programm, das ich geschrieben habe, um Enums einfach in Strings zu konvertieren. Es ist einfach zu bedienen und benötigt ca. 5 Sekunden, um es fertig zu stellen (einschließlich der Zeit, um in das Verzeichnis mit dem Programm zu cd, dann führen Sie es aus und übergeben Sie ihm die Datei mit der Aufzählung).
Hier herunterladen: http://www.mediafire.com/?nttignoozzz
Diskussionsthema dazu hier: http://cboard.cprogramming.com/projects-job-recruitment/127488-free-program-im-sharing-convertenumtostrings.html
Führen Sie das Programm mit dem Argument "--help" aus, um eine Beschreibung der Verwendung zu erhalten.
quelle
Vor nicht allzu langer Zeit habe ich einen Trick gemacht, um Enums korrekt in QComboBox anzuzeigen und die Definition von Enum- und String-Darstellungen als eine Anweisung zu haben
Jetzt können Sie
enumeration::enum_singleton<your_enum>::instance()
Aufzählungen in Zeichenfolgen konvertieren. Wenn Sie ersetzenkv_storage_t
mitboost::bimap
, werden Sie auch rückwärts Umwandlung der Lage zu tun. Die allgemeine Basisklasse für den Konverter wurde eingeführt, um sie im Qt-Objekt zu speichern, da Qt-Objekte keine Vorlagen sein konntenVorheriger Auftritt
quelle
Verwenden Sie als Variante die einfache lib> http://codeproject.com/Articles/42035/Enum-to-String-and-Vice-Versa-in-C
Im Code
Zeilen hinzufügen
Funktionieren Sie einwandfrei , wenn die Werte in enum nicht veröffentlicht sind .
Anwendungsbeispiel
und umgekehrt
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
quelle