Introduction
C++enum
s lack some features that coders often need. For example, the value of the last member to be able to iterate through the possible values of anenum
. This problem is usually solved by adding a "last
" member to theenum
:
enum MyEnum{ MyEnum_member1, MyEnum_member2, MyEnum_Last};
Another thing that causes headaches is the conversion between anenum
value and itsstring
representation. Most people, especially beginners, end up with something like this to be able to perform the conversion:
staticconstchar* ENUM_STRINGS[MyEnum_Last] ={"MyEnum_member1","MyEnum_member2",};
The code attached to this article provides a solution to these problems. It has been tested with VS2008 and CygWin g++ 4.5.0.
Using the Code
Using the code is simple; just include theSmartEnum.h file in your project (maybe in yourstdafx.h), and then declare yourenum
s with the macros provided inSmartEnum.h, like this:
BEGIN_SMART_ENUM(MyEnum) ENUM_MEMBER(member1) ENUM_MEMBER(member2)END_SMART_ENUM(MyEnum)
You can place thisenum
declaration anywhere, inside class declarations and namespaces as well as you can do with C++enum
s. With the aboveenum
declaration, the following code snippets demonstrate how thisenum
solves the problems that are present when using C++enum
s.
Using yourenum
members:
MyEnum e = MyEnum::member1;
Iterating through the members of theenum
:
for (MyEnum i=MyEnum::FIRST; i<MyEnum::LAST; ++i) printf("%d. MyEnum::%s\n", (int)i, i.ToString());
Now you also have some predefined constants and methods in theMyEnum
"namespace", these are:
MyEnum::FIRSTMyEnum::LAST == MyEnum::COUNT == MyEnum::INVALID
You also have some useful methods:
staticconstchar* MyEnum::ToString(const MyEnum& e);constchar* MyEnum::ToString()const;static MyEnum MyEnum::FromString(constchar* s);staticbool MyEnum::IsValid(const MyEnum& e);bool MyEnum::IsValid()const;// pre- and postfix -- and ++ operators required to iterate
Other useful methods can be added that are required by your project (e.g.:Serialize
).
A cool thing is that thisenum
is automatically initialized toMyEnum::INVALID
so as to make it easier to avoid the common error of leaving anenum
uninitialized.
When a program has manyenum
s with similar member names, programmers can easily make the mistake of comparing twoenum
values of different types. This results in syntactically valid but buggy C++ code that actually compiles, maybe with a warning message. A C++enum
can also be compared with C++ integers. A smartenum
submitted in this article can normally be compared only to the same type; you have to cast it to a primitive integral type if you want to do otherwise.
Disadvantages
The solution has some limitations; let's go through them:
- The value of the
enum
is stored in a primitive C++ type (char
) that makes debugging more difficult. To overcome this, I put in a (const char*
) that always points to the name of the member when compiled in debug mode, thus making the size of theenum
different in Debug/Release builds. - The underlying template metaprogram limits the number of
enum
members to32
. - These macros generate code that compile much slower than a normal C++
enum
. - Currently,
FromString()
is O(n); it could be made O(log(n)). Doing so would bring on thread safety issues, so for now, I've chosen this simpler solution. - The members cannot have custom values as with regular C++
enum
s.
History
- 13 November, 2010: Initial release