Contrary to all other similar questions, this question is about using the new C++ features.
- 2008 c Is there a simple way to convert C++ enum to string?
- 2008 c Easy way to use variables of enum types as string in C?
- 2008 c++ How to easily map c++ enums to strings
- 2008 c++ Making something both a C identifier and a string?
- 2008 c++ Is there a simple script to convert C++ enum to string?
- 2009 c++ How to use enums as flags in C++?
- 2011 c++ How to convert an enum type variable to a string?
- 2011 c++ Enum to String C++
- 2011 c++ How to convert an enum type variable to a string?
- 2012 c How to convert enum names to string in c
- 2013 c Stringifying an conditionally compiled enum in C
After reading many answers, I did not yet find any:
- Elegant way using C++11, C++14 or C++17 new features
- Or something ready-to-use in Boost
- Else something planned for C++20
Example
An example is often better than a long explanation.
You can compile and run this snippet on Coliru.
(Another former example is also available)
#include <map>
#include <iostream>
struct MyClass
{
enum class MyEnum : char {
AAA = -8,
BBB = '8',
CCC = AAA + BBB
};
};
// Replace magic() by some faster compile-time generated code
// (you're allowed to replace the return type with std::string
// if that's easier for you)
const char* magic (MyClass::MyEnum e)
{
const std::map<MyClass::MyEnum,const char*> MyEnumStrings {
{ MyClass::MyEnum::AAA, "MyClass::MyEnum::AAA" },
{ MyClass::MyEnum::BBB, "MyClass::MyEnum::BBB" },
{ MyClass::MyEnum::CCC, "MyClass::MyEnum::CCC" }
};
auto it = MyEnumStrings.find(e);
return it == MyEnumStrings.end() ? "Out of range" : it->second;
}
int main()
{
std::cout << magic(MyClass::MyEnum::AAA) <<'\n';
std::cout << magic(MyClass::MyEnum::BBB) <<'\n';
std::cout << magic(MyClass::MyEnum::CCC) <<'\n';
}
Constraints
- Please no valueless duplication of other answers or basic link.
- Please avoid bloat macro-based answer, or try to reduce the
#define
overhead as minimum as possible. - Please no manual
enum
->string
mapping.
Nice to have
- Support
enum
values starting from a number different from zero - Support negative
enum
values - Support fragmented
enum
values - Support
class enum
(C++11) - Support
class enum : <type>
having any allowed<type>
(C++11) - Compile-time (not run-time) conversions to a string,
or at least fast execution at run-time (e.g.std::map
is not a great idea…) constexpr
(C++11, then relaxed in C++14/17/20)noexcept
(C++11)- C++17/C++20 friendly snippet
One possible idea could be using the C++ compiler capabilities to generate C++ code at compilation-time using meta-programming tricks based on variadic template class
and constexpr
functions…
Best Solution
(The approach of the better_enums library)
There is a way to do enum to string in current C++ that looks like this:
Usage:
All operations can be made
constexpr
. You can also implement the C++17 reflection proposal mentioned in the answer by @ecatmur.#
) is the only way to convert a token to a string in current C++.constexpr
. It can also be made to work with C++98 +__VA_ARGS__
. It is definitely modern C++.The macro's definition is somewhat involved, so I'm answering this in several ways.
It is straightforward to extend this answer to the features of the library – nothing "important" is left out here. It is, however, quite tedious, and there are compiler portability concerns.
Disclaimer: I am the author of both the CodeProject article and the library.
You can try the code in this answer, the library, and the implementation of N4428 live online in Wandbox. The library documentation also contains an overview of how to use it as N4428, which explains the enums portion of that proposal.
Explanation
The code below implements conversions between enums and strings. However, it can be extended to do other things as well, such as iteration. This answer wraps an enum in a
struct
. You can also generate a traitsstruct
alongside an enum instead.The strategy is to generate something like this:
The problems are:
{Red = 1, Green, Blue}
as the initializer for the values array. This is not valid C++, becauseRed
is not an assignable expression. This is solved by casting each constant to a typeT
that has an assignment operator, but will drop the assignment:{(T)Red = 1, (T)Green, (T)Blue}
.{"Red = 1", "Green", "Blue"}
as the initializer for the names array. We will need to trim off the" = 1"
. I am not aware of a great way to do this at compile time, so we will defer this to run time. As a result,_to_string
won't beconstexpr
, but_from_string
can still beconstexpr
, because we can treat whitespace and equals signs as terminators when comparing with untrimmed strings.__VA_ARGS__
. This is pretty standard. This answer includes a simple version that can handle up to 8 elements.constexpr
(or justconst
) arrays at namespace scope, or regular arrays in non-constexpr
static inline functions. The code in this answer is for C++11 and takes the former approach. The CodeProject article is for C++98 and takes the latter.Code
and
The program above prints
Red
, as you would expect. There is a degree of type safety, since you can't create an enum without initializing it, and deleting one of the cases from theswitch
will result in a warning from the compiler (depending on your compiler and flags). Also, note that"Red"
was converted to an enum during compilation.