Voici ce que j'essaye de faire:
typedef enum { ONE, TWO, THREE } Numbers;
J'essaie d'écrire une fonction qui ferait un cas de commutation similaire à ce qui suit:
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;
}
Au lieu de définir à chaque cas, existe-t-il un moyen de le définir en utilisant la variable enum comme j'essaie de le faire ci-dessus?
c
enums
c-preprocessor
zxcv
la source
la source
La technique de faire quelque chose à la fois un identifiant C et une chaîne? peut être utilisé ici.
Comme d'habitude avec de tels trucs de préprocesseur, écrire et comprendre la partie préprocesseur peut être difficile, et comprend le passage de macros à d'autres macros et implique l'utilisation des opérateurs # et ##, mais son utilisation est vraiment facile. Je trouve ce style très utile pour les énumérations longues, où maintenir deux fois la même liste peut être vraiment gênant.
Code d'usine - tapé une seule fois, généralement caché dans l'en-tête:
enumFactory.h:
Usine utilisée
someEnum.h:
someEnum.cpp:
La technique peut être facilement étendue afin que les macros XX acceptent plus d'arguments, et vous pouvez également avoir préparé plus de macros pour remplacer XX pour des besoins différents, similaires aux trois que j'ai fournis dans cet exemple.
Comparaison avec les X-Macros utilisant #include / #define / #undef
Bien que cela soit similaire aux X-Macros que d'autres ont mentionnés, je pense que cette solution est plus élégante en ce qu'elle ne nécessite rien #undefing, ce qui vous permet de cacher plus de choses compliquées dans l'usine le fichier d'en-tête - le fichier d'en-tête est quelque chose que vous ne touchez pas du tout lorsque vous devez définir une nouvelle énumération, donc la nouvelle définition d'énumération est beaucoup plus courte et plus propre.
la source
SOME_ENUM(XX)
est exactement une X-macro (pour être précis, le "formulaire utilisateur" qui passe laXX
fonction plutôt que d'utiliser#def
#undef
) et ensuite à son tour le X-MACRO entier est ensuite passé à DEFINE_ENUM qui l'utilise. Ne rien enlever à la solution - cela fonctionne bien. Juste pour clarifier qu'il s'agit d'une utilisation de macros X.XX
la réing#define
est que l'ancien modèle peut être utilisé dans les extensions macro. Notez que les seules autres solutions aussi concises que celle-ci nécessitent toutes la création et l'inclusion multiple d'un fichier séparé pour définir une nouvelle énumération.#define DEFINE_ENUM(EnumType) ...
, remplacerENUM_DEF(...)
parEnumType(...)
et faire dire à l'utilisateur#define SomeEnum(XX) ...
. Le préprocesseur C se développera contextuellementSomeEnum
dans l'appel de la macro lorsqu'il est suivi de parenthèses et dans un jeton régulier dans le cas contraire. (Bien sûr, cela pose des problèmes si l'utilisateur aime utiliserSomeEnum(2)
pour lancer le type enum plutôt que(SomeEnum)2
oustatic_cast<SomeEnum>(2)
.)#define
et#undef
. Êtes-vous en désaccord avec le fait que le «formulaire utilisateur» (suggéré par exemple au bas de cet article ) est un type de x-macro? Je l'ai certainement toujours appelé une x-macro et dans les bases de code C dans lesquelles j'ai été récemment, c'est la forme la plus courante (c'est évidemment une observation biaisée). J'ai peut-être mal analysé l'OP.la source
#define ENUM_END(typ) }; extern const char * typ ## _name_table[];
dans ledefs.h
fichier - cela déclarera votre table de noms dans les fichiers que vous l'utilisez. (Je ne peux pas trouver un bon moyen de déclarer la taille de la table, cependant.) De plus, personnellement, je laisserais le point-virgule final, mais les mérites sont discutables de toute façon.typ
dans la ligne#define ENUM_END(typ) };
?Il existe certainement un moyen de le faire - utilisez les macros X () . Ces macros utilisent le préprocesseur C pour construire des énumérations, des tableaux et des blocs de code à partir d'une liste de données source. Il vous suffit d'ajouter de nouveaux éléments à la #define contenant la macro X (). L'instruction switch se développerait automatiquement.
Votre exemple peut s'écrire comme suit:
Il existe des moyens plus efficaces (c'est-à-dire utiliser des macros X pour créer un tableau de chaînes et un index enum), mais c'est la démonstration la plus simple.
la source
Je sais que vous avez quelques bonnes réponses solides, mais connaissez-vous l'opérateur # dans le préprocesseur C?
Il vous permet de faire ceci:
la source
char const *kConstStr[]
C ou C ++ ne fournit pas cette fonctionnalité, même si j'en ai souvent besoin.
Le code suivant fonctionne, bien qu'il soit mieux adapté aux énumérations non éparses.
Par non clairsemé, je veux dire pas de la forme
car cela comporte d'énormes lacunes.
L'avantage de cette méthode est qu'elle rapproche les définitions des énumérations et des chaînes; avoir une instruction switch dans une fonction les lance. Cela signifie que vous êtes moins susceptible de changer l'un sans l'autre.
la source
BAISER. Vous ferez toutes sortes d'autres choses avec vos enums, alors pourquoi l'impression devrait-elle être différente? Oublier un cas dans votre routine d'impression n'est pas un problème si l'on considère qu'il y a environ 100 autres endroits où vous pouvez oublier un cas. Compilez simplement -Wall, qui avertira des correspondances de cas non exhaustives. N'utilisez pas "default" car cela rendra le commutateur exhaustif et vous n'obtiendrez pas d'avertissements. Au lieu de cela, laissez le commutateur se fermer et gérez le cas par défaut comme ceci ...
la source
Essayez de convertir les énumérations C ++ en chaînes . Les commentaires ont des améliorations qui résolvent le problème lorsque les éléments énumérés ont des valeurs arbitraires.
la source
L'utilisation de boost :: preprocessor rend possible une solution élégante comme la suivante:
Étape 1: inclure le fichier d'en-tête:
Étape 2: déclarez l'objet d'énumération avec la syntaxe suivante:
Étape 3: utilisez vos données:
Obtenir le nombre d'éléments:
Obtention de la chaîne associée:
Obtenir la valeur enum de la chaîne associée:
Cela semble propre et compact, sans fichiers supplémentaires à inclure. Le code que j'ai écrit dans EnumUtilities.h est le suivant:
Il y a quelques limitations, à savoir celles de boost :: preprocessor. Dans ce cas, la liste des constantes ne peut pas dépasser 64 éléments.
En suivant la même logique, vous pouvez également penser à créer une énumération éparse:
Dans ce cas, la syntaxe est:
L'utilisation est similaire à celle ci-dessus (moins la fonction eName ## 2Enum, que vous pourriez essayer d'extrapoler à partir de la syntaxe précédente).
Je l'ai testé sur mac et linux, mais sachez que boost :: preprocessor n'est peut-être pas entièrement portable.
la source
En fusionnant certaines des techniques ici, j'ai trouvé la forme la plus simple:
la source
Si vous utilisez gcc, il est possible d'utiliser:
Alors appelez simplement par exemple
la source
Découvrez les idées dans Mu Dynamics Research Labs - Blog Archive . J'ai trouvé cela plus tôt cette année - j'oublie le contexte exact où je l'ai rencontré - et je l'ai adapté dans ce code. Nous pouvons débattre de l'intérêt d'ajouter un E à l'avant; il est applicable au problème spécifique traité, mais ne fait pas partie d'une solution générale. Je l'ai caché dans mon dossier «vignettes» - où je garde des bribes de code intéressantes au cas où je les voudrais plus tard. J'ai honte de dire que je n'ai pas gardé une note de l'origine de cette idée à l'époque.
En-tête: paste1.h
Exemple de source:
Ce n'est pas nécessairement l'utilisation la plus propre au monde du préprocesseur C - mais cela empêche l'écriture du matériel plusieurs fois.
la source
Faire quelque chose à la fois d'un identifiant C et d'une chaîne
la source
Si l'index enum est basé sur 0, vous pouvez placer les noms dans un tableau de char * et les indexer avec la valeur enum.
la source
Discussion supplémentaire sur cette méthode
Astuces de directive de préprocesseur pour les nouveaux arrivants
la source
J'ai créé une classe simple basé sur un modèle
streamable_enum
que les utilisations flux opérateurs<<
et>>
et est basé sur lestd::map<Enum, std::string>
:Usage:
la source
Voici une solution utilisant des macros avec les fonctionnalités suivantes:
n'écrivez chaque valeur de l'énumération qu'une seule fois, il n'y a donc pas de double liste à maintenir
ne gardez pas les valeurs d'énumération dans un fichier séparé qui sera plus tard #inclus, afin que je puisse l'écrire où je veux
ne remplacez pas l'énumération elle-même, je veux toujours que le type enum soit défini, mais en plus de cela, je veux pouvoir mapper chaque nom enum à la chaîne correspondante (pour ne pas affecter le code hérité)
la recherche doit être rapide, donc de préférence pas de boîtier de commutation, pour ces énormes énumérations
https://stackoverflow.com/a/20134475/1812866
la source
Je pensais qu'une solution comme Boost.Fusion one pour adapter les structures et les classes serait bien, ils l'ont même eue à un moment donné, d'utiliser les énumérations comme une séquence de fusion.
J'ai donc fait quelques petites macros pour générer le code pour imprimer les énumérations. Ce n'est pas parfait et n'a rien à voir avec le code standard généré par Boost.Fusion, mais peut être utilisé comme les macros Boost Fusion. Je veux vraiment faire générer les types nécessaires à Boost.Fusion à intégrer dans cette infrastructure qui permet d'imprimer les noms des membres de la structure, mais cela se produira plus tard, pour l'instant ce ne sont que des macros:
L'ancienne réponse ci-dessous est plutôt mauvaise, veuillez ne pas l'utiliser. :)
Ancienne réponse:
J'ai cherché un moyen de résoudre ce problème sans trop changer la syntaxe de la déclaration enums. Je suis venu à une solution qui utilise le préprocesseur pour récupérer une chaîne à partir d'une déclaration d'énumération stringifiée.
Je suis capable de définir des énumérations non éparses comme ceci:
Et je peux interagir avec eux de différentes manières:
Basé sur les définitions suivantes:
Quand j'aurai besoin de support pour les enum clairsemés et quand j'aurai plus de temps , j'améliorerai les implémentations to_string et from_string avec boost :: xpressive, mais cela coûtera en temps de compilation en raison de l'important templating effectué et l'exécutable généré est susceptible d'être vraiment plus grand. Mais cela a l'avantage qu'il sera plus lisible et maintenable que ce vilain code de manipulation manuelle de chaînes.:RÉ
Sinon, j'ai toujours utilisé boost :: bimap pour effectuer de tels mappages entre la valeur enums et la chaîne, mais il doit être maintenu manuellement.
la source
Parce que je préfère ne pas utiliser de macros pour toutes les raisons habituelles, j'ai utilisé une solution de macro plus limitée qui a l'avantage de garder la macro de déclaration enum libre. Les inconvénients comprennent le fait de devoir copier-coller la définition de macro pour chaque énumération et d'ajouter explicitement un appel de macro lors de l'ajout de valeurs à l'énumération.
la source