[c++] How to Get enum item name from its value

I declared a enum type as this,

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

How can I get the item name "Mon, Tue, etc" when I already have the item value "0, 1, etc."

I already have a function as this

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

And now I want the output below

Today is Wed, enjoy

This question is related to c++ enums

The answer is


You can define an operator that performs the output.

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

If you know the actual enum labels correlated to their values, you can use containers and C++17's std::string_view to quickly access values and their string representations with the [ ] operator while tracking it yourself. std::string_view will only allocate memory when created. They can also be designated with static constexpr if you want them available at run-time for more performance savings. This little console app should be fairly fast.

#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;
}

Output:

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

You can't directly, enum in C++ are not like Java enums.

The usual approach is to create a std::map<WeekEnum,std::string>.

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

Here is another neat trick to define enum using 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;
}

Live Demo: https://ideone.com/bPAVTM

Outputs:

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

The solution I prefer is to mix arrays and ostream like this:

std::ostream& operator<<(std::ostream& lhs, WeekEnum e) {
    static const std::array<std::string, 7> WEEK_STRINGS = {"Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday" };

    return os << WEEK_STRINGS[statuc_cast<WeekEnum>(e)]
}

cout << "Today is " << WeekEnum::Monday;

I also suggest to use enum class instead of Enum


How can I get the item name "Mon, Tue, etc" when I already have the item value "0, 1, etc."

On some older C code (quite some time ago), I found code analogous to:

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: This establishes a "pathological dependency" between the enumeration values and the function... meaning if you change the enum you must change the function to match. I suppose this is true even for a std::map.

I vaguely remember we found a utility to generate the function code from the enum code. The enum table length had grown to several hundred ... and at some point it is maybe a sound choice to write code to write code.


Note -

in an embedded system enhancement effort, my team replaced many tables (100+?) of null-terminated-strings used to map enum int values to their text strings.

The problem with the tables was that a value out of range was often not noticed because many of these tables were gathered into one region of code / memory, such that a value out-of-range reached past the named table end(s) and returned a null-terminated-string from some subsequent table.

Using the function-with-switch statement also allowed us to add an assert in the default clause of the switch. The asserts found several more coding errors during test, and our asserts were tied into a static-ram-system-log our field techs could search.


An enumeration is something of an inverse-array. What I believe you want is this:

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.

On GCC it may look like this:

const char* WeekEnumNames [] = {
    [Mon] = "Mon",
    [Tue] = "Tue",
    [Wed] = "Wed",
    [Thu] = "Thu",
    [Fri] = "Fri",
    [Sat] = "Sat",
    [Sun] = "Sun",
};

No, you have no way to get the "name" from the value in C++ because all the symbols are discarded during compilation.

You may need this way X Macros


I have had excellent success with a technique which resembles the X macros pointed to by @RolandXu. We made heavy use of the stringize operator, too. The technique mitigates the maintenance nightmare when you have an application domain where items appear both as strings and as numerical tokens.

It comes in particularily handy when machine readable documentation is available so that the macro X(...) lines can be auto-generated. A new documentation would immediately result in a consistent program update covering the strings, enums and the dictionaries translating between them in both directions. (We were dealing with PCL6 tokens).

And while the preprocessor code looks pretty ugly, all those technicalities can be hidden in the header files which never have to be touched again, and neither do the source files. Everything is type safe. The only thing that changes is a text file containing all the X(...) lines, and that is possibly auto generated.