Enum to String and vice versa - Enum.Parse alternative for C++
Original Article Link: http://www.codeproject.com/Articles/42035/Enum-to-String-and-Vice-Versa-in-C
Update: Link to Source.
However, all the solutions I found suffered from one or more of the following:
Let's say we wanted to create an
Now we can convert from a
If you look at the declarations of the helper macros, you'll see that the definition of the
Update: Link to Source.
Introduction
While adding Serialization support to my project, I realized that I would require some way to convert astring
to an enumerator and vice versa. So I did a Google search for the same, and found a lot of information; different ways in which people implemented this functionality.However, all the solutions I found suffered from one or more of the following:
- No support for enumerators with non-contiguous values
- No support (not even partial support) for enumerators with duplicate values
- No support for existing enumerations (without modifying their source code)
- Requires one or more extra files per enumeration
- Requires source-code to be pre-processed (by a custom binary) before compilation
- Difficult to use or maintain
- Highly susceptible to typos
- Is platform/compiler specific (not portable)
How To Use the Code
Using the code is quite easy. All we need to do is add one file: EnumString.h (see the source code accompanying this article) to our project.Let's say we wanted to create an
enum
to represent one of the Furious Five Masters (Kung Fu Panda (2008) anyone?). So we go ahead and declare it as usual:
Collapse | Copy Code
// Furious Five Master enum Master { Tigress = 5, Viper = 3, Monkey = 4, Mantis = 1, Crane = 2 };
Don't worry about the values assigned, they are simply my rough idea of what the 'mass' of each master is, in some imaginary units. Now to add stringizing support, we need to declare the enum
again, but in a different format (uses helper macros):
Collapse | Copy Code
// String support for Furious Five Master Begin_Enum_String( Master ) { Enum_String( Tigress ); Enum_String( Viper ); Enum_String( Monkey ); Enum_String( Mantis ); Enum_String( Crane ); } End_Enum_String;
And we're done! Note that since this second declaration lies in the same header/source file as the actual enum
definition (probably declared just below it), it's not that difficult to update it whenever we modify the actual enumeration.Now we can convert from a
string
to a Master
enumerator and vice versa, quite easily. The following code shows how to do that:
Collapse | Copy Code
// Convert from a Master enumerator to a string const std::string &masterStr = EnumString<Master>::From( Monkey ); assert( masterStr.compare( "Monkey" ) == 0 ); // Convert from a string to a Master enumerator Master master = Tigress; const bool bResult = EnumString<Master>::To( master, masterStr ); assert( bResult == true ); assert( master == Monkey );
Using the Code with Existing Enumerations
Suppose we want to add stringizing support to an existing enumeration from a library, which is namespaced. Imagine that theenum
is declared like this in the library:
Collapse | Copy Code
namespace SomeLibrary { enum WeekEnd { Sunday = 1, Saturday = 7 }; }
Say that we can't modify the library files (which is anyway not a good practice). So we create a separate header file in our project, in which we will declare stringizing support for the required library enum
. For the declaration, we have 3 options: Option 1 - Fully Qualify All the Names
Collapse | Copy Code
Begin_Enum_String( SomeLibrary::WeekEnd ) { Enum_String( SomeLibrary::Sunday ); Enum_String( SomeLibrary::Saturday ); } End_Enum_String;
The consequence of this is that the stringized enum
s will also be fully qualified names. So, the statement EnumString<WeekEnd>::From( SomeLibrary::Saturday )
will yield "SomeLibrary::Saturday
", and not just "Saturday
".Option 2 - Use the 'using namespace' Directive
Collapse | Copy Code
using namespace SomeLibrary; Begin_Enum_String( WeekEnd ) { Enum_String( Sunday ); Enum_String( Saturday ); } End_Enum_String;
Option 3 - Register the Enumerators Yourself
Without using the 'Enum_String
' helper macro (see the next section 'How does it actually work?', for an explanation of this):
Collapse | Copy Code
Begin_Enum_String( SomeLibrary::WeekEnd ) { RegisterEnumerator( SomeLibrary::Sunday, "Sunday" ); RegisterEnumerator( SomeLibrary::Saturday, "Saturday" ); } End_Enum_String;
How Does It Actually Work?
It's not required to know how it works in order to use it, so those who are not really interested can skip this section. Also, beginners might have to brush up on their C++ before reading this.If you look at the declarations of the helper macros, you'll see that the definition of the
string
support for FuriousFiveMaster, works out to the following:
Collapse | Copy Code
template <> struct EnumString<Master> : public EnumStringBase< EnumString<Master>, Master > { static void RegisterEnumerators() { RegisterEnumerator( Tigress, "Tigress" ); RegisterEnumerator( Viper, "Viper" ); RegisterEnumerator( Monkey, "Monkey" ); RegisterEnumerator( Mantis, "Mantis" ); RegisterEnumerator( Crane, "Crane" ); } }
You might have already realized that the above is a specialization of the EnumString
template class. It defines the RegisterEnumerators
function which is used by its base class EnumStringBase
, via CRTP. Now the workings of the usage become clear. When you use the functions EnumString<Master>::From or EnumString<Master>::To
, you're using the version of the EnumString
template class which is specialized with the Master
enumeration.Drawbacks
As with most things, the code does have some drawbacks. The two most important ones are:- Doesn't support conversion of enumerators with duplicate values to
string
s (although vice versa works just fine). An attempt to convert such an enumerator will yield an emptystring
(which can be tested for). - Conversion performance might be a bottleneck for some applications. A single
std::map
is used internally for storing the relationship of enumerators to theirstring
representations. So lookups during conversions are not in constant time. A conversion from an enumerator to astring
will be in linear time, although a vice versa conversion should be very fast.
Closing
Since the code makes extensive use of templates, it may not work with older compilers. The code has been tested with the following compilers:- Microsoft Visual C++ 2005/2008
- GCC 4.4.0
References
- http://www.gamedev.net/community/forums/topic.asp?topic_id=351014
- http://www.gamedev.net/community/forums/topic.asp?topic_id=501798
- http://www.gamedev.net/community/forums/topic.asp?topic_id=437852
- http://www.edm2.com/0405/enumeration.html
- C___enums_to_strings.aspx
- http://www.codeguru.com/cpp/cpp/cpp_mfc/article.php/c4001
Comments
Post a Comment