Frage

Dies ist für die C Präprozessor Experten:

Wie kann ich eine enum mit einer Liste von einigen Bezeichner deklarieren und später während der Schalter-Anweisung zu überprüfen, ob eine Kennung in der Liste enthält?

Beispiel von dem, was ich brauche:

typedef enum { e1, e2, e3, e4, e5, e6 } e;

e x;
switch (x) {
#if DECLARED_IN_ENUM (e1)
  case e1 : ...
#endif
  /* etc. */
}

Ich dachte an eine Boost-Sequenz verwendet und in eine durch Kommata getrennte Liste in der ENUM-Erweiterung, aber wie kann ich später prüfen, ob die Sequenz, die einen bestimmten Token enthält?

Bearbeiten : Was ich in der Lage war, mit Boost-zu tun ist:

#define e1 e1
#define e2 e2
#define e3 e3
#define e4 e4
#define e5 e5
#define e6 e6
#define E (e1)(e2)(e3)(e4)(e5)(e6)

typedef enum { BOOST_PP_SEQ_ENUM(E) } e;

e x;
switch (x) {
#if defined (e1)
  case e1 : ...
#endif
  /* etc. */
}

Das ist nicht sehr schön, und ich möchte lieber etwas:

#define E (e1)(e2)(e3)(e4)(e5)(e6)

typedef enum { BOOST_PP_SEQ_ENUM(E) } e;

e x;
switch (x) {
#if BOOST_PP_SEQ_CONTAINS (e1,E)
  case e1 : ...
#endif
  /* etc. */
}

aber wie implementiert BOOST_PP_SEQ_CONTAINS werden könnte?

War es hilfreich?

Lösung

Ich glaube nicht, BOOST_PP_SEQ_CONTAINS umgesetzt werden kann. Es müssten Sie der Lage sein, Token zu vergleichen zwei Sequenzen von Vorverarbeitung, die Sie nicht tun können.

Wenn Sie jedoch Ihre Logik ein bisschen neu anordnen, können Sie etwas näher an, was Sie wollen. Zuerst müssen wir ein paar Helfer Makros für die Verwendung mit BOOST_PP_SEQ_FOR_EACH:

#include <boost/preprocessor.hpp>

// General purpose macros:
#define EXPAND_ENUM_CASE_2(text1, text2) text1 ## text2
#define EXPAND_ENUM_CASE(r, data, elem) \
    case elem : EXPAND_ENUM_CASE_2(data ## _ ## CASE ## _ , elem)

Wir können die Liste der Aufzählungen definieren und die Aufzählung genauso wie in der ursprünglichen Frage:

#define WORKDAY_ENUMERATORS (Monday)(Tuesday)(Wednesday)(Thursday)

enum Workday { BOOST_PP_SEQ_ENUM(WORKDAY_ENUMERATORS) }; 

Wie Sie sehen können, habe ich Freitag links von der Liste ab, weil niemand tut tatsächlich Arbeit am Freitag. Betrachten wir als Beispiel eine Funktion, dass die Renditen etwas Text, den Tag der Woche zu beschreiben.

Statt der Prüfung, ob ein Enumerator in die Liste aufgenommen wurde, definieren wir die Fälle für jeden der Werte mit Hilfe von Makros:

#define WORKDAY_CASE_Monday    { return "Mondays suck";                     }
#define WORKDAY_CASE_Tuesday   { return "Tuesdays are better than Mondays"; }
#define WORKDAY_CASE_Wednesday { return "Hooray for humpday!";              }
#define WORKDAY_CASE_Thursday  { return "Thursdays are okay";               }
#define WORKDAY_CASE_Friday    { return "No one really works on Friday";    }

Wir erzeugen dann die richtigen case-Anweisungen für die Liste des WORKDAY_ENUMERATORS verwenden und die Enumeratoren mit dem WORKDAY_CASE_ Präfix verketten:

const char* get_day_text(Workday d)
{    
    switch (d)
    {
        BOOST_PP_SEQ_FOR_EACH(EXPAND_ENUM_CASE, WORKDAY, WORKDAY_ENUMERATORS)
    }
    return "WTF?!  That's not a workday!";
}

Wenn ein Tag nicht in der WORKDAY_ENUMERATORS Liste aufgenommen wurde, wird kein Fall für sie erzeugt werden.

Weil wir höflich sein sollte, wenn wir den Präprozessor verwenden wir dann undefine Makros wir verwendet:

#undef WORKDAY_CASE_Monday
#undef WORKDAY_CASE_Tuesday
#undef WORKDAY_CASE_Wednesday
#undef WORKDAY_CASE_Thursday
#undef WORKDAY_CASE_Friday

Ich denke, diese Art von hässlich ist, aber es ist eine Möglichkeit, fast um die Ergebnisse zu bekommen Sie suchen.

Andere Tipps

Sie können nicht. Der C-Präprozessor nicht „verstehen“ die C-Programmiersprache, es tokenizes es einfach. Es weiß nicht, was „Enum“ eigentlich bedeutet. Der Compiler behandelt, die eine.

Wenn Sie im Preprocessor zu Test etwas wollen, dann werden Sie haben Präprozessormakros bereitzustellen, um es zu benutzen.

Edit: sorry, vermisst, dass Sie Boost.Preprocessor verwenden beabsichtigen. Ich weiß nicht, ob das die erforderlichen Makros zur Verfügung stellen kann, oder nicht, wenn Sie beteiligt etwas von Boost-in der Definition Ihrer ENUM haben.

Verwenden Sie einfach enum nicht. Es dient keinem nützlichen Zweck. Deklarieren Sie alle Ihre Konstanten mit #define und Verwendung #ifdef.

Ein Ansatz ist es, eine große große #define oder „.h“ Datei zu haben, die alle Ihre Wochentage umfasst (die H-Datei hat den Vorteil, dass Sie nicht brauchen, um alle Gleichen mit Backslash) und enthält alle relevanten Informationen für sie in Makros. Dann #define den Generator Makro, etwas zu tun, rufen Sie das große Makro (oder # include den Header), #undef Generator Makro- und definieren es etwas anderes zu tun, rufen Sie das große Makro wieder, usw. In diesem Szenario einer Variation ":; break; func_foo () Fall ENUM_foo" der Generator Makro wäre so etwas wie erzeugen. Sie könnten dann alle den entsprechenden Code für die entsprechende func_ * Funktionen schreiben und sie würden als angemessen bezeichnet werden.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top