J'ai un tas de types d'énumérations dans certains fichiers d'en-tête de bibliothèque que j'utilise, et je veux avoir un moyen de convertir les valeurs d'énumération en chaînes utilisateur - et vice-versa.
RTTI ne le fera pas pour moi, car les «chaînes utilisateur» doivent être un peu plus lisibles que les énumérations.
Une solution de force brute serait un tas de fonctions comme celle-ci, mais je pense que c'est un peu trop C-like.
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");
}
}
J'ai le sentiment instinctif qu'il existe une solution élégante utilisant des modèles, mais je ne peux pas encore tout à fait comprendre.
MISE À JOUR: Merci pour vos suggestions - j'aurais dû préciser que les énumérations sont définies dans un en-tête de bibliothèque tiers, donc je ne veux pas avoir à en changer la définition.
Mon instinct est maintenant d'éviter les modèles et de faire quelque chose comme ceci:
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);
Réponses:
Si vous voulez que les noms d'énumérations eux-mêmes soient des chaînes, consultez cet article . Sinon, ça
std::map<MyEnum, char const*>
fonctionnera bien. (Inutile de copier vos littéraux de chaîne dans std :: strings dans la carte)Pour plus de sucre syntaxique, voici comment écrire une classe map_init. Le but est de permettre
La fonction
template <typename T> map_init(T&)
renvoie unmap_init_helper<T>
.map_init_helper<T>
stocke un T &, et définit le trivialmap_init_helper& operator()(typename T::key_type const&, typename T::value_type const&)
. (Le retour*this
deoperator()
permet le chaînage deoperator()
, commeoperator<<
surstd::ostream
s)Étant donné que la fonction et la classe d'assistance sont basées sur un modèle, vous pouvez les utiliser pour n'importe quelle carte ou structure de type carte. Ie il peut également ajouter des entrées à
std::unordered_map
Si vous n'aimez pas écrire ces helpers, boost :: assign offre la même fonctionnalité prête à l'emploi.
la source
La solution MSalters est bonne, mais elle se réinstalle essentiellement
boost::assign::map_list_of
. Si vous avez boost, vous pouvez l'utiliser directement:la source
eee
dans votre cas.error: template declaration of 'const boost::unordered::unordered_map<T, const char*> enumToString'
.Générer automatiquement un formulaire à partir d'un autre.
La source:
Généré:
Si les valeurs d'énumération sont grandes, un formulaire généré pourrait utiliser unordered_map <> ou des modèles comme suggéré par Constantin.
La source:
Généré:
Exemple:
la source
Je me souviens avoir répondu à cela ailleurs sur StackOverflow. Répétez-le ici. En gros, c'est une solution basée sur des macros variadiques, et est assez facile à utiliser:
Pour l'utiliser dans votre code, faites simplement:
la source
Je suggère qu'un mélange d'utilisation de X-macros est la meilleure solution et les fonctions de modèle suivantes:
Pour emprunter marcinkoziukmyopenidcom et prolongé
colour.def
la source
J'utilise cette solution que je reproduis ci-dessous:
la source
Si vous souhaitez obtenir des représentations sous forme de chaîne de
MyEnum
variables , les modèles ne le couperont pas. Le modèle peut être spécialisé sur les valeurs intégrales connues au moment de la compilation.Cependant, si c'est ce que vous voulez, essayez:
C'est verbeux, mais attrapera des erreurs comme celle que vous avez faite en question - votre
case VAL1
est dupliqué.la source
J'ai passé plus de temps à faire des recherches sur ce sujet que j'aimerais admettre. Heureusement, il existe d'excellentes solutions open source dans la nature.
Ce sont deux grandes approches, même si elles ne sont pas (encore) assez connues,
sage_enum
Meilleurs énumérations
la source
Je serais tenté d'avoir une carte m - et l'incorporer dans l'énumération.
setup avec m [MyEnum.VAL1] = "Valeur 1";
et tout est fait.
la source
J'ai eu besoin de cette fonctionnalité plusieurs fois pour déboguer / analyser le code des autres. Pour cela, j'ai écrit un script Perl qui génère une classe avec plusieurs
toString
méthodes surchargées . ChaquetoString
méthode prend unEnum
comme argument et retourneconst char*
.Bien sûr, le script n'analyse pas C ++ pour les énumérations lui-même, mais utilise des ctags pour générer une table de symboles.
Le script Perl est ici: http://heinitz-it.de/download/enum2string/enum2string.pl.html
la source
Vos réponses m'ont inspiré à écrire moi-même des macros. Mes exigences étaient les 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
Ce code crée une énumération classique avec certaines valeurs. De plus, il crée comme std :: map qui mappe chaque valeur d'énumération à son nom (ie map [E_SUNDAY] = "E_SUNDAY", etc.)
Ok, voici le code maintenant:
EnumUtilsImpl.h :
EnumUtils.h // c'est le fichier que vous voulez inclure chaque fois que vous aurez besoin de faire cela, vous utiliserez les macros de celui-ci:
MyProjectCodeFile.h // ceci est un exemple de la façon de l'utiliser pour créer une énumération personnalisée:
À votre santé.
la source
Voici une tentative pour obtenir automatiquement les opérateurs de flux << et >> sur enum avec une commande de macro d'une seule ligne ...
Définitions:
Usage:
Je ne suis pas sûr des limites de ce système ... les commentaires sont les bienvenus!
la source
dans l'en-tête:
dans le fichier .cpp:
Avertissement: ne gérez pas un mauvais index de tableau. :) Mais vous pouvez facilement ajouter une fonction pour vérifier l'énumération avant d'obtenir la chaîne du tableau.
la source
Je voulais juste montrer cette solution élégante possible à l'aide de macros. Cela ne résout pas le problème, mais je pense que c'est un bon moyen de repenser le problème.
---- ÉDITER ----
Après quelques recherches sur Internet et quelques expériences personnelles, je suis arrivé à la solution suivante:
Je voulais juste le poster, peut-être que quelqu'un pourrait trouver cette solution utile. Il n'y a pas besoin de classes de modèles, pas besoin de c ++ 11 et pas besoin de boost donc cela pourrait également être utilisé pour de simples C.
---- EDIT2 ----
la table d'informations peut produire des problèmes lors de l'utilisation de plus de 2 énumérations (problème du compilateur). La solution de contournement suivante a fonctionné:
la source
Ci-dessus, ma solution simple. Un avantage de celui-ci est le «NUM» qui contrôle la taille du tableau de messages, il empêche également l'accès hors des limites (si vous l'utilisez à bon escient).
Vous pouvez également définir une fonction pour obtenir la chaîne:
Suite à ma solution, j'ai alors trouvé la suivante assez intéressante. Il a généralement résolu le problème de synchronisation de celui ci-dessus.
Diapositives ici: http://www.slideshare.net/arunksaha/touchless-enum-tostring-28684724
Code ici: https://github.com/arunksaha/enum_to_string
la source
Je sais que je suis en retard pour faire la fête, mais pour tous les autres qui viennent visiter cette page, vous pouvez essayer ceci, c'est plus facile que tout et cela a plus de sens:
la source
J'ai récemment eu le même problème avec une bibliothèque fournisseur (Fincad). Heureusement, le fournisseur a fourni une documentation XML pour toutes les énumérations. J'ai fini par générer une carte pour chaque type d'énumération et fournir une fonction de recherche pour chaque énumération. Cette technique vous permet également d'intercepter une recherche en dehors de la plage de l'énumération.
Je suis sûr que swig pourrait faire quelque chose de similaire pour vous, mais je suis heureux de fournir les utilitaires de génération de code qui sont écrits en ruby.
Voici un exemple de code:
On dirait que vous voulez aller dans l'autre sens (enum to string, plutôt que string to enum), mais cela devrait être trivial à inverser.
-Brin
la source
Voyez si la syntaxe suivante vous convient:
Si tel est le cas, vous voudrez peut-être consulter cet article:
http://www.gamedev.net/reference/snippets/features/cppstringizing/
la source
ce bon vieux désordre est mon effort basé sur des morceaux et des morceaux de SO. Le for_each devrait être développé pour prendre en charge plus de 20 valeurs d'énumération. Je l'ai testé sur Visual Studio 2019, clang et gcc. c ++ 11
qui produit le code suivant
Dommage que vous ayez à sauter avec le préprocesseur pour faire cela dans l'un des langages de programmation les plus utilisés au monde ...
la source
En utilisant des initialiseurs de tableau désignés, votre tableau de chaînes est indépendant de l'ordre des éléments dans l'énumération:
la source