En C#, y’a un truc qui dechire, c’est la fonction ToString() sur des enums.
Lorsqu’un programmeur C++ voit ca pour la premiere fois, ca degoutte un peu tant de simplicite apres en avoir bave tant a lier des enums a des string. Sans compter le enum.Parse qui enfonse le clou. Car il faut bien le dire c’est un peu la galere en C++ de gerer ca sans avoir de desynchro.
Allez, courage mes amis programmeur C++, tenez bon y’a toujours des astuces pour survivre de facon convenable dans ce monde cruel et sans pitie.
Generallement lorsqu’on veut associer un string a un enum en C++, on cree deux definitions:
enum ALPHABET
{
eA,
eB,
…etc
};
const char *LABEL
{
“Lettre A”,
“Lettre B”,
…etc
};
Le problem classique de ce genre d’approche c’est que lorsqu’un mec passe derriere, il ajoutte un enum a la fin (ou au milieu!) et apres ca devient la galere a etre sur que ca soit toujours synchronise avec le texte, car y’a deux (voir des fois plus) endroits a toucher a la fois.
Solution 1: #include
Ceux qui trainaient sur mon vieux site savent que j’avais une solution a la MacGuyver y’a longtemps qui comprenait l’utilisation d’un #include et d’une definition de macro.
Grosso modo, ca consistait en ca:
Creer un fichier MonFichier.txt, dont le contenu etait le suivant:
MACRO(a)
MACRO(b)
…etc
Puis dans le fichier .h (generallement) ou on defnit l’enum, on redefinie la macro comme on le souhaite avant d’inclure le fichier:
#define MACRO(x) e#x,
enum ALPHABET
{
#include “MonFichier.txt”
};
#undef MACRO
Puis on fait la meme chose (generallement dans le .cpp) pour le texte avec MACRO definie autrement:
#define MACRO(x) “Lettre ##x”,
const char *LABEL
{
#include “MonFichier.txt”
};
#undef MACRO
Du coup on a plus qu’une place a changer (MonFichier.txt) pour ajoutter/modifier l’enumeration et on est sur que c’est toujours synchrone. La classe quoi…
La solution est efficace, mais elle a le desavantage de demander un autre fichier et empeche une grosse divergenre entre le texte et les enums.
Ex: on peut pas avoir comme label: “A comme ange” et “B comme Bebe”.
Sans oublier que intelli-pasintelli-sense est totallement perdu.
Solution 2: Le double macro combo.
Retenez votre respiration, voila la soluition a deux niveaux de macro:
define MYLIST(x) \
x(eA, “A comme Ange”) \
x(eB, “B comme Bebe”) \
…etc
#define UTILISE_PREMIER_ELEMENT(x, y) x,
#define UTILISE_DEUXIEME_ELEMENT(x, y) y,
enum ALPHABET
{
MYLIST(UTILISE_PREMIER_ELEMENT)
};
const char LABEL[] =
{
MYLIST( UTILISE_DEUXIEME_ELEMENT)
};
Maintenant le concept est simple lorsqu’on se met a la place du compilateur et qu’on fait deux passes:
Premiere passe, le compilateur va remplacer les MYLIST par ce qu’on a mis dans MYLIST:
enum ALPHABET
{
UTILISE_PREMIER_ELEMENT(eA, “A comme Ange”)
UTILISE_PREMIER_ELEMENT(eB, “B comme Bebe”)
…etc
};
const char LABEL[] =
{
UTILISE_DEUXIEME_ELEMENT(eA, “A comme Ange”)
UTILISE_DEUXIEME_ELEMENT(eB, “B comme Bebe”)
…etc
};
La deuxieme passe sera fatale, on va obtenir ce qu’on veut car le compilateur va remplacer les autres macros (UTILISE_PREMIER_ELEMENT et UTILISE_DEUXIEME_ELEMENT).
enum ALPHABET
{
eA,
eB,
…etc
};
const char LABEL[] =
{
“A comme Ange”,
“B comme Bebe”,
…etc
};
Le programmeur C# peut aller se rhabiller. On a une facon plutot sympa maintenant en C++ de groupper ensemble dans une definition du style tableau autant de donnees qu’on veut.
Car rien ne nous empeche de declarer une troiseme dimension (et plus) en ayant une fonction qui soit liee a cet enum (pratique pour la lecture de fichier binaire par exemple) et d’appliquer cette meme technique de double macro.
define MYLIST(x) \
x(eA, “A comme Ange”, &Alphabet::ProcessA) \
x(eB, “B comme Bebe”, &Alphabet::ProcessB) \
…etc
#define UTILISE_PREMIER_ELEMENT(x, y, z) x,
#define UTILISE_DEUXIEME_ELEMENT(x, y, z) y,
#define UTILISE_TROISIEME_ELEMENT(x, y, z) z,
Voila, plus qu’a ramasser le mouchoir et s’essuyer les larmes de bonheur des programmeurs C++ frustres et maltraite avec les enums depuis des annees.
Sur ce, bon code et si vous avez encore une meilleur solutions, je suis toute ouie, mouchoir a la main
Hé mais c’est excellent comme idée ça, belle trouvaille! Jusqu’à présent le mieux que j’avais trouvé c’était ta première solution, et effectivement Intellisense apprécie moyen.
Merci pour le tips, jusqu’à présent j’utilisais une fonction ToString pour chaque enum avec un bon gros switch… et c’était la galère
Super l’astuce.
Une simple question, si je ne dispose que de la chaine de caractère, comment je retrouve enum en int associé. Par exemple, une variable comporte “A comme Ange” et je souhaite récupérer dans un int le eA associé ?
Encore merci.
Avec une for loop, un truc genre:
int i;
for (i = 0; i < sizeof(LABEL)/sizeof(char*); ++i)
puis tu _strnicmp avec ton eA, une fois trouve, tu break et ton enum est egal a (ALPHABET)i
(ou tu peux avoir un enum pour la fin, genre eFIN que tu peux utiliser dans tes loop)