web-dev-qa-db-fra.com

Comment obtenir le nom d'un élément enum à partir de sa valeur

J'ai déclaré un type enum comme ceci,

enum WeekEnum
{
Mon = 0;
Tue = 1;
Wed = 2;
Thu = 3;
Fri = 4;
Sat = 5;
Sun = 6;
};

Comment puis-je obtenir le nom de l'article "Lundi, mardi, etc." alors que j'ai déjà la valeur de l'article "0, 1, etc."

J'ai déjà une fonction comme celle-ci

Log(Today is "2", enjoy! );

Et maintenant je veux la sortie ci-dessous

Aujourd'hui est mercredi, profitez-en

26
Nano HE

Vous ne pouvez pas directement, enum en C++ ne sont pas comme des énumérations Java. 

L’approche habituelle consiste à créer un std::map<WeekEnum,std::string>.

std::map<WeekEnum,std::string> m;
m[Mon] = "Monday";
//...
m[Sun] = "Sunday";
22
Luchian Grigore

non, vous n'avez aucun moyen d'obtenir le "nom" de la valeur en C++ car tous les symboles sont ignorés lors de la compilation. 

Vous aurez peut-être besoin de cette façon X Macros

9
RolandXu

Une énumération est une sorte de tableau inverse. Ce que je crois que tu veux, c'est ceci:

const char * Week[] = { "", "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" };  // The blank string at the beginning is so that Sunday is 1 instead of 0.
cout << "Today is " << Week[2] << ", enjoy!";  // Or whatever you'de like to do with it.
7
Cosine

Vous pouvez définir un opérateur qui effectue la sortie.

std::ostream& operator<<(std::ostream& lhs, WeekEnum e) {
    switch(e) {
    case Monday: lhs << "Monday"; break;
    .. etc
    }
    return lhs;
}
6
Puppy

Voici une autre astuce pour définir enum en utilisant X Macro:

#include <iostream>

#define WEEK_DAYS \
X(MON, "Monday", true) \
X(TUE, "Tuesday", true) \
X(WED, "Wednesday", true) \
X(THU, "Thursday", true) \
X(FRI, "Friday", true) \
X(SAT, "Saturday", false) \
X(Sun, "Sunday", false)

#define X(day, name, workday) day,
enum WeekDay : size_t
{
    WEEK_DAYS
};
#undef X

#define X(day, name, workday) name,
char const *weekday_name[] =
{
    WEEK_DAYS
};
#undef X

#define X(day, name, workday) workday,
bool weekday_workday[]
{
    WEEK_DAYS
};
#undef X

int main()
{
    std::cout << "Enum value: " << WeekDay::THU << std::endl;
    std::cout << "Name string: " << weekday_name[WeekDay::THU] << std::endl;
    std::cout << std::boolalpha << "Work day: " << weekday_workday[WeekDay::THU] << std::endl;

    WeekDay wd = Sun;
    std::cout << "Enum value: " << wd << std::endl;
    std::cout << "Name string: " << weekday_name[wd] << std::endl;
    std::cout << std::boolalpha << "Work day: " << weekday_workday[wd] << std::endl;

    return 0;
}

Démo en direct: https://ideone.com/bPAVTM

Les sorties:

Enum value: 3
Name string: Thursday
Work day: true
Enum value: 6
Name string: Sunday
Work day: false
3
Killzone Kid

Comment puis-je obtenir le nom de l'article "Lundi, mardi, etc." alors que j'ai déjà le valeur de l'objet "0, 1, etc."

Sur un code C plus ancien (il y a quelque temps), j'ai trouvé un code analogue à:

std::string weekEnumToStr(int n)
{
   std::string s("unknown");
   switch (n)
   {
   case 0: { s = "Mon"; } break;
   case 1: { s = "Tue"; } break;
   case 2: { s = "Wed"; } break;
   case 3: { s = "Thu"; } break;
   case 4: { s = "Fri"; } break;
   case 5: { s = "Sat"; } break;
   case 6: { s = "Sun"; } break;
   }
   return s;
}

Con: Ceci établit une "dépendance pathologique" entre les valeurs d'énumération et la fonction ... ce qui signifie que si vous modifiez l'énumération, vous devez modifier la fonction pour qu'elle corresponde. Je suppose que cela est vrai même pour un std :: map. 

Je me souviens vaguement que nous avons trouvé un utilitaire permettant de générer le code de fonction à partir du code enum. La longueur de la table enum avait atteint plusieurs centaines ... et à un moment donné, il est peut-être un choix judicieux d'écrire du code pour écrire du code. 


Remarque - 

dans un effort d'amélioration du système intégré, mon équipe a remplacé de nombreuses tables (plus de 100?) de chaînes à terminaison nulle utilisées pour mapper les valeurs enum int sur leurs chaînes de texte.

Le problème avec les tables était qu’une valeur hors limites n’était souvent pas remarquée car beaucoup de ces tables étaient rassemblées dans une région de code/mémoire, de sorte qu’une valeur hors de portée dépassait les extrémités de la table nommée et a renvoyé une chaîne terminée par null à partir d'une table ultérieure. 

L'utilisation de l'instruction function-with-switch nous a également permis d'ajouter une assertion dans la clause par défaut du commutateur. Les assertions ont révélé plusieurs autres erreurs de codage pendant le test, et nos assertions ont été liées dans un journal système statique-ram-système que nos techniciens sur le terrain pourraient rechercher. 

1
2785528

Si vous connaissez les étiquettes d'énumération réelles corrélées à leurs valeurs, vous pouvez utiliser des conteneurs et le std::string_view de C++ 17 pour accéder rapidement aux valeurs et à leurs représentations de chaîne avec l'opérateur [] tout en effectuant un suivi vous-même. std::string_view n'allouera de la mémoire qu'une fois créé. Ils peuvent également être désignés avec static constexpr si vous voulez qu'ils soient disponibles au moment de l'exécution pour davantage d'économies de performances. Cette petite application console devrait être assez rapide.

#include <iostream>
#include <string_view>
#include <Tuple>    
int main() {
    enum class Weekdays { //default behavior starts at 0 and iterates by 1 per entry
        Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday
    };

    static constexpr std::string_view Monday    = "Monday";
    static constexpr std::string_view Tuesday   = "Tuesday";
    static constexpr std::string_view Wednesday = "Wednesday";
    static constexpr std::string_view Thursday  = "Thursday";
    static constexpr std::string_view Friday    = "Friday";
    static constexpr std::string_view Saturday  = "Saturday";
    static constexpr std::string_view Sunday    = "Sunday";
    static constexpr std::string_view opener    = "enum[";
    static constexpr std::string_view closer    = "] is ";
    static constexpr std::string_view semi      = ":";

    std::pair<Weekdays, std::string_view> Weekdays_List[] = {
        std::make_pair(Weekdays::Monday,    Monday),
        std::make_pair(Weekdays::Tuesday,   Tuesday),
        std::make_pair(Weekdays::Wednesday, Wednesday),
        std::make_pair(Weekdays::Thursday,  Thursday),
        std::make_pair(Weekdays::Friday,    Friday),
        std::make_pair(Weekdays::Saturday,  Saturday),
        std::make_pair(Weekdays::Sunday,    Sunday)
    };

    for (int i=0;i<sizeof(Weekdays_List)/sizeof(Weekdays_List[0]);i++) {
        std::cout<<opener<<i<<closer<<Weekdays_List[(int)i].second<<semi\
        <<(int)Weekdays_List[(int)i].first<<std::endl;
    }    
    return 0;
}

Sortie: 

enum[0] is Monday:0
enum[1] is Tuesday:1
enum[2] is Wednesday:2
enum[3] is Thursday:3
enum[4] is Friday:4
enum[5] is Saturday:5
enum[6] is Sunday:6
0

J'ai eu un excellent succès avec une technique qui ressemble aux macros X indiquées par @RolandXu. Nous avons également beaucoup utilisé l'opérateur stringize. La technique atténue le cauchemar de maintenance lorsque vous avez un domaine d'application dans lequel les éléments apparaissent à la fois sous forme de chaînes et de jetons numériques.

C'est particulièrement pratique lorsque la documentation lisible par machine est disponible, de sorte que les macros X(...) puissent être générées automatiquement. Une nouvelle documentation aboutirait immédiatement à une mise à jour cohérente du programme couvrant les chaînes, les enums et les dictionnaires traduisant entre eux dans les deux sens. (Nous avons eu affaire à des jetons PCL6).

Et bien que le code du préprocesseur ait l'air assez laid, toutes ces technicités peuvent être cachées dans les fichiers d'en-tête qui ne doivent plus jamais être touchés, pas plus que les fichiers source. Tout est de type sécuritaire. La seule chose qui change est un fichier texte contenant toutes les lignes X(...), qui est éventuellement généré automatiquement.

0
Peter A. Schneider