Folgendes versuche ich zu tun:
typedef enum { ONE, TWO, THREE } Numbers;
Ich versuche, eine Funktion zu schreiben, die einen Schalterfall ähnlich dem folgenden ausführt:
char num_str[10];
int process_numbers_str(Numbers num) {
switch(num) {
case ONE:
case TWO:
case THREE:
{
strcpy(num_str, num); //some way to get the symbolic constant name in here?
} break;
default:
return 0; //no match
return 1;
}
Gibt es eine Möglichkeit, anstatt in jedem Fall zu definieren, die Enum-Variable wie oben beschrieben festzulegen?
c
enums
c-preprocessor
zxcv
quelle
quelle
Die Technik, etwas sowohl zu einem C-Bezeichner als auch zu einem String zu machen? kann hier verwendet werden.
Wie bei solchen Präprozessor-Inhalten üblich, kann das Schreiben und Verstehen des Präprozessor-Teils schwierig sein. Dazu gehört das Übergeben von Makros an andere Makros und die Verwendung von Operatoren # und ##, aber die Verwendung ist sehr einfach. Ich finde diesen Stil sehr nützlich für lange Aufzählungen, bei denen es sehr mühsam sein kann, dieselbe Liste zweimal zu pflegen.
Werkscode - nur einmal eingegeben, normalerweise in der Kopfzeile versteckt:
enumFactory.h:
Werkseitig verwendet
someEnum.h:
someEnum.cpp:
Die Technik kann leicht erweitert werden, sodass XX-Makros mehr Argumente akzeptieren, und Sie können auch mehr Makros vorbereitet haben, um XX für unterschiedliche Anforderungen zu ersetzen, ähnlich den drei, die ich in diesem Beispiel bereitgestellt habe.
Vergleich mit X-Makros mit #include / #define / #undef
Dies ähnelt zwar den X-Makros, die andere erwähnt haben, aber ich denke, diese Lösung ist eleganter, da sie kein #undefing erfordert, wodurch Sie mehr von den komplizierten Dingen verstecken können, die in der Fabrik die Header-Datei - die Header-Datei - enthält ist etwas, das Sie überhaupt nicht berühren, wenn Sie eine neue Aufzählung definieren müssen, daher ist die neue Aufzählungsdefinition viel kürzer und sauberer.
quelle
SOME_ENUM(XX)
ist genau ein X-Makro (um genau zu sein, das "Benutzerformular", das dieXX
Funktion übergibt , anstatt sie zu verwenden#def
#undef
), und dann wird wiederum das gesamte X-MACRO an DEFINE_ENUM übergeben, das es verwendet. Der Lösung nichts wegzunehmen - es funktioniert gut. Nur um zu verdeutlichen, dass es sich um eine Verwendung von X-Makros handelt.XX
über Wieder#define
ing ist , dass das frühere Muster in Makroerweiterungen verwendet werden kann. Beachten Sie, dass die einzigen anderen Lösungen, die so präzise sind wie diese, die Erstellung und mehrfache Aufnahme einer separaten Datei erfordern, um eine neue Aufzählung zu definieren.#define DEFINE_ENUM(EnumType) ...
, ersetzen SieENUM_DEF(...)
mitEnumType(...)
und den Benutzer zu sagen haben#define SomeEnum(XX) ...
. Der C-Präprozessor wird kontextuellSomeEnum
in den Makroaufruf erweitert, wenn Klammern folgen, andernfalls in ein reguläres Token. (Dies verursacht natürlich Probleme, wenn der Benutzer lieber inSomeEnum(2)
den Aufzählungstyp als in(SomeEnum)2
oderstatic_cast<SomeEnum>(2)
#define
und#undef
. Stimmen Sie jedoch nicht zu, dass das "Benutzerformular" (vorgeschlagen zum Beispiel am Ende dieses Artikels ) eine Art X-Makro ist? Ich habe es sicherlich auch immer als x-Makro bezeichnet und in den C-Codebasen, in denen ich in letzter Zeit war, ist es die häufigste Form (das ist offensichtlich eine voreingenommene Beobachtung). Möglicherweise habe ich das OP falsch analysiert.quelle
#define ENUM_END(typ) }; extern const char * typ ## _name_table[];
indefs.h
Datei - Dadurch wird Ihre Namenstabelle in den von Ihnen verwendeten Dateien deklariert. (Ich kann jedoch keinen guten Weg finden, um die Tabellengröße zu deklarieren.) Auch persönlich würde ich das letzte Semikolon weglassen, aber die Vorzüge sind in beiden Fällen umstritten.typ
in der Leitung beschäftigen#define ENUM_END(typ) };
?Es gibt definitiv eine Möglichkeit, dies zu tun - verwenden Sie X () -Makros . Diese Makros verwenden den C-Präprozessor, um Aufzählungen, Arrays und Codeblöcke aus einer Liste von Quelldaten zu erstellen. Sie müssen der #define, die das X () -Makro enthält, nur neue Elemente hinzufügen. Die switch-Anweisung wird automatisch erweitert.
Ihr Beispiel kann wie folgt geschrieben werden:
Es gibt effizientere Möglichkeiten (z. B. die Verwendung von X-Makros zum Erstellen eines String-Arrays und eines Enum-Index), dies ist jedoch die einfachste Demo.
quelle
Ich weiß, dass Sie ein paar gute, solide Antworten haben, aber kennen Sie den Operator # im C-Präprozessor?
Damit können Sie Folgendes tun:
quelle
char const *kConstStr[]
C oder C ++ bietet diese Funktionalität nicht, obwohl ich sie oft gebraucht habe.
Der folgende Code funktioniert, obwohl er am besten für nicht spärliche Aufzählungen geeignet ist.
Mit nicht spärlich meine ich nicht von der Form
da hat das große lücken.
Der Vorteil dieser Methode besteht darin, dass die Definitionen der Aufzählungen und Zeichenfolgen nahe beieinander liegen. Eine switch-Anweisung in einer Funktion speariert sie. Dies bedeutet, dass Sie weniger wahrscheinlich eines ohne das andere ändern.
quelle
KUSS. Sie werden alle möglichen anderen Switch / Case-Dinge mit Ihren Aufzählungen tun. Warum sollte das Drucken anders sein? Das Vergessen eines Falls in Ihrer Druckroutine ist keine große Sache, wenn Sie bedenken, dass es ungefähr 100 andere Stellen gibt, an denen Sie einen Fall vergessen können. Kompilieren Sie einfach -Wall, um vor nicht erschöpfenden Fallübereinstimmungen zu warnen. Verwenden Sie nicht "Standard", da dies den Schalter erschöpfend macht und Sie keine Warnungen erhalten. Lassen Sie stattdessen den Schalter beenden und behandeln Sie den Standardfall wie folgt ...
quelle
Versuchen Sie, C ++ - Aufzählungen in Zeichenfolgen zu konvertieren . Die Kommentare enthalten Verbesserungen, die das Problem lösen, wenn Aufzählungselemente beliebige Werte haben.
quelle
Die Verwendung von boost :: preprocessor ermöglicht eine elegante Lösung wie die folgende:
Schritt 1: Fügen Sie die Header-Datei hinzu:
Schritt 2: Deklarieren Sie das Aufzählungsobjekt mit der folgenden Syntax:
Schritt 3: Verwenden Sie Ihre Daten:
Ermitteln der Anzahl der Elemente:
Abrufen der zugehörigen Zeichenfolge:
Abrufen des Aufzählungswerts aus der zugehörigen Zeichenfolge:
Dies sieht sauber und kompakt aus, ohne dass zusätzliche Dateien enthalten sein müssen. Der Code, den ich in EnumUtilities.h geschrieben habe, lautet wie folgt:
Es gibt einige Einschränkungen, z. B. die von boost :: preprocessor. In diesem Fall darf die Liste der Konstanten nicht größer als 64 Elemente sein.
Nach der gleichen Logik könnten Sie auch daran denken, eine spärliche Aufzählung zu erstellen:
In diesem Fall lautet die Syntax:
Die Verwendung ist ähnlich wie oben (abzüglich der Funktion eName ## 2Enum, die Sie versuchen könnten, aus der vorherigen Syntax zu extrapolieren).
Ich habe es auf Mac und Linux getestet, aber beachten Sie, dass boost :: preprocessor möglicherweise nicht vollständig portierbar ist.
quelle
Durch das Zusammenführen einiger Techniken hier habe ich die einfachste Form gefunden:
quelle
Wenn Sie gcc verwenden, können Sie Folgendes verwenden:
Dann rufen Sie einfach zum Beispiel an
quelle
Schauen Sie sich die Ideen im Mu Dynamics Research Labs - Blog Archive an . Ich habe dies Anfang dieses Jahres gefunden - ich vergesse den genauen Kontext, in dem ich darauf gestoßen bin - und habe es in diesen Code angepasst. Wir können die Vorzüge des Hinzufügens eines E an der Front diskutieren. Es gilt für das jeweilige Problem, ist jedoch nicht Teil einer allgemeinen Lösung. Ich habe dies in meinem 'Vignetten'-Ordner aufbewahrt - wo ich interessante Codefetzen aufbewahre, falls ich sie später haben möchte. Es ist mir peinlich zu sagen, dass ich nicht notiert habe, woher diese Idee damals kam.
Header: paste1.h
Beispielquelle:
Dies ist nicht unbedingt die weltweit sauberste Verwendung des C-Vorprozessors - verhindert jedoch, dass das Material mehrmals ausgeschrieben wird.
quelle
Machen Sie etwas sowohl zu einem C-Bezeichner als auch zu einer Zeichenfolge
quelle
Wenn der Aufzählungsindex auf 0 basiert, können Sie die Namen in ein Array von char * einfügen und mit dem Aufzählungswert indizieren.
quelle
Weitere Diskussion zu dieser Methode
Tricks der Präprozessor-Direktive für Neulinge
quelle
Ich habe eine einfache Template - Klasse erstellt ,
streamable_enum
dass Anwendungen streamen Operatoren<<
und>>
und basiert auf derstd::map<Enum, std::string>
:Verwendung:
quelle
Hier ist eine Lösung mit Makros mit den folgenden Funktionen:
Schreiben Sie jeden Wert der Aufzählung nur einmal, sodass keine doppelten Listen gepflegt werden müssen
Bewahren Sie die Enum-Werte 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 keinen Einfluss auf den Legacy-Code zu haben).
Die Suche sollte schnell sein, also vorzugsweise kein Switch-Case für diese riesigen Aufzählungen
https://stackoverflow.com/a/20134475/1812866
quelle
Ich dachte, dass eine Lösung wie Boost.Fusion eine für die Anpassung von Strukturen und Klassen wäre schön, sie hatten es sogar irgendwann, Aufzählungen als Fusionssequenz zu verwenden.
Also habe ich nur ein paar kleine Makros erstellt, um den Code zum Drucken der Aufzählungen zu generieren. Dies ist nicht perfekt und hat mit Boost.Fusion-generiertem Boilerplate-Code nichts zu sehen, kann aber wie die Boost Fusion-Makros verwendet werden. Ich möchte wirklich die Typen generieren, die von Boost.Fusion für die Integration in diese Infrastruktur benötigt werden, die das Drucken von Namen von Strukturelementen ermöglicht, aber dies wird später geschehen, im Moment sind dies nur Makros:
Die alte Antwort unten ist ziemlich schlecht, bitte benutze das nicht. :) :)
Alte Antwort:
Ich habe nach einem Weg gesucht, der dieses Problem löst, ohne die Syntax der Enums-Deklaration zu stark zu ändern. Ich bin zu einer Lösung gekommen, die den Präprozessor verwendet, um eine Zeichenfolge aus einer stringifizierten Enumerationsdeklaration abzurufen.
Ich kann nicht spärliche Aufzählungen wie folgt definieren:
Und ich kann auf verschiedene Arten mit ihnen interagieren:
Basierend auf folgenden Definitionen:
Wenn ich Unterstützung für spärliche Aufzählungen benötige und mehr Zeit habe, werde ich die Implementierungen to_string und from_string mit boost :: xpressive verbessern. Dies kostet jedoch Kompilierungszeit, da wichtige Vorlagen erstellt und die ausführbare Datei generiert werden wahrscheinlich wirklich größer sein. Dies hat jedoch den Vorteil, dass es besser lesbar und wartbar ist als dieser hässliche manuelle Code zur Manipulation von Zeichenfolgen. : D.
Ansonsten habe ich immer boost :: bimap verwendet, um solche Zuordnungen zwischen enums value und string durchzuführen, aber es muss manuell gepflegt werden.
quelle
Da ich aus den üblichen Gründen keine Makros verwenden möchte, habe ich eine eingeschränktere Makrolösung verwendet, die den Vorteil hat, dass das Makro für die Aufzählungsdeklaration frei bleibt. Zu den Nachteilen gehört das Kopieren, Einfügen der Makrodefinition für jede Aufzählung und das explizite Hinzufügen eines Makroaufrufs beim Hinzufügen von Werten zur Aufzählung.
quelle