Enum to string in C++11
The longstanding and unnecessary lack of a generic enum-to-string feature in C++ (and C) is a painful one. C++11 didn't address this, and as far as I know neither will C++14.
Personally I'd solve this problem using code generation. The C preprocessor is one way--you can see some other answers linked in the comments here for that. But really I prefer to just write my own code generation specifically for enums. It can then easily generate to_string (char*)
, from_string
, ostream operator<<
, istream operator<<
, is_valid
, and more methods as needed. This approach can be very flexible and powerful, yet it enforces absolute consistency across many enums in a project, and it incurs no runtime cost.
Do it using Python's excellent "mako" package, or in Lua if you're into lightweight, or the CPP if you're against dependencies, or CMake's own facilities for generating code. Lots of ways, but it all comes down to the same thing: you need to generate the code yourself--C++ won't do this for you (unfortunately).
In my opinion, the most maintainable approach is to write a helper function:
const char* get_name(OS_type os) {
switch (os) {
case Linux: return "Linux";
case Apple: return "Apple";
case Windows: return "Windows";
}
}
It is a good idea not to implement the "default" case, since doing so will ensure that you get a compiler warning if you forget to implement a case (with the right compiler and compiler settings).
I like a hack using the C preprocessor, which I first saw here: http://blogs.msdn.com/b/vcblog/archive/2008/04/30/enums-macros-unicode-and-token-pasting.aspx .
It uses the token-pasting operator # .
// This code defines the enumerated values:
#define MY_ENUM(x) x,
enum Fruit_Type {
MY_ENUM(Banana)
MY_ENUM(Apple)
MY_ENUM(Orange)
};
#undef MY_ENUM
// and this code defines an array of string literals for them:
#define MY_ENUM(x) #x,
const char* const fruit_name[] = {
MY_ENUM(Banana)
MY_ENUM(Apple)
MY_ENUM(Orange)
};
#undef MY_ENUM
// Finally, here is some client code:
std::cout << fruit_name[Banana] << " is enum #" << Banana << "\n";
// In practice, those three "MY_ENUM" macro calls will be inside an #include file.
Frankly, it's ugly and. but you end up typing your enums exactly ONCE in an include file, which is more maintainable.
BTW, on that MSDN blog link (see above) a user made a comment with a trick that makes the whole thing much prettier, and avoids #includes:
#define Fruits(FOO) \
FOO(Apple) \
FOO(Banana) \
FOO(Orange)
#define DO_DESCRIPTION(e) #e,
#define DO_ENUM(e) e,
char* FruitDescription[] = {
Fruits(DO_DESCRIPTION)
};
enum Fruit_Type {
Fruits(DO_ENUM)
};
// Client code:
std::cout << FruitDescription[Banana] << " is enum #" << Banana << "\n";
(I just noticed that 0x17de's answer also uses the token-pasting operator)