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 invaluable 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, relaxed in C++14)noexcept
(C++11)- snippet C++14/C++17 friendly
- C++ State of the art
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...
EDIT: check below for a newer version
As mentioned above, N4113 is the final solution to this matter, but we'll have to wait more than a year to see it coming out.
Meanwhile, if you want such feature, you'll need to resort to "simple" templates and some preprocessor magic.
Enumerator
Usage
Simple explaination
Enum<T>::m_counter
is set to 0 inside each namespace declaration.(Could someone point me out where ^^this behaviour^^ is mentioned on the standard?)
The preprocessor magic automates the declaration of enumerators.
Disadvantages
enum
type, therefore not promotable to intAlternative solution
This one sacrifices line numbering (not really) but can be used on switch cases.
Errata
#line 0
conflicts with-pedantic
on GCC and clang.Workaround
Either start at
#line 1
and subtract 1 from__LINE__
.Or, don't use
-pedantic
.And while we're at it, avoid VC++ at all costs, it has always been a joke of a compiler.
Usage
Real-life implementation and use
r3dVoxel - Enum
r3dVoxel - ELoggingLevel
Quick Reference
#line lineno -- cppreference.com
example
automatically ENUM_MAKE macro generate 'enum class' and helper class with 'enum reflection function'.
In order to reduce mistakes, at once Everything is defined with only one ENUM_MAKE.
The advantage of this code is automatically created for reflection and a close look at macro code ,easy-to-understand code. 'enum to string' , 'string to enum' performance both is algorithm O(1).
Disadvantages is when first use , helper class for enum relection 's string vector and map is initialized. but If you want you'll also be pre-initialized. –
What about a simple streaming overload? You still have to maintain the mapping if you don't want to do some macro magic, but I find it cleaner than your original solution.
Very simple solution with one big constraint: you can't assign custom values to
enum
values, but with the right regex, you could. you could also add a map to translate them back toenum
values without much more effort:Usage example:
For
C++17C++20, you will be interested in the work of the Reflection Study Group (SG7). There is a parallel series of papers covering wording (P0194) and rationale, design and evolution (P0385). (Links resolve to the latest paper in each series.)As of P0194r2 (2016-10-15), the syntax would use the proposed
reflexpr
keyword:For example (adapted from Matus Choclik's reflexpr branch of clang):
Static reflection failed to make it into C++17 (rather, into the probably-final draft presented at the November 2016 standards meeting in Issaquah) but there is confidence that it will make it into C++20; from Herb Sutter's trip report:
(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.