After reading the abstract about a generic wrapper for C enums for boost, I knew I had to start using such concept in my own library ocfc. However the following points were missing in the proposal:
- Enum values are defined in global scope as are C enums. This can be ok if you are writing a simple and small program but in large project global values are a no-no. How many times can you have the following kind of enums: LEFT, RIGHT, TOP, BOTTOM! I think it is much better if enum values are scoped to the enum class i.e. my_enum::LEFT or my_enum::RIGHT.
- No debugging helpers such as when converting int to enum.
- No string description for each enum which comes handy when accepting values from user or displaying an error message!
- No straight forward way to define non-continuous enum values.
- No way to expand the notion of enums from one value to a structure. I means by that that as soon as you associate a description string to an enum value you could also associate other information!
I therefore decided to craft my own version of smart_enum to take account of the above points. The resulting source is available here taken out of ocfc library.
So now how do you use my basic_enum class? Let's start with a simple enum. In your header you declare your enum as follows:
DECLARE_ENUM(my_enum, LEFT = 0, TOP = 2, RIGHT = 3, BOTTOM = 5)
Then in your code implementation you include the following:
IMPLEMENT_ENUM(my_enum,
ENUM_ITEM(LEFT)
ENUM_ITEM(TOP),
ENUM_ITEM(RIGHT),
ENUM_ITEM(BOTTOM)
)
I know that compared with boost implementation you need to declare AND implement your enum but the benefit outweights this downside. Now here what you can do for instance to initialize a variable of type my_enum.
my_enum __initialize_with_enum = my_enum::BOTTOM;
my_enum __initialize_with_string = _T("BOTTOM");
my_enum __initialize_with_integer = 5;
Comparison and increment operators are of course present as you would expect:
my_enum __e; // initialized with first value
++__e;
__e--;
__e = __e + 2; // an exception will be thrown if enum becomes out of range
if (__e == my_enum::LEFT)
std_out << _T("__e = ") << __e.str()
As you see from the code above that to get the enum value as a string is as simple as calling str() member function on the enum instance. To iterate over each enum value simply write the following:
for (my_enum::const_iterator __i = my_enum::begin(); __i != my_enum::end(); ++__i)
std_out << __i->str() << _T(" = ") << __i->value();
Ok let's now associate an extra value with each enum as in this next example.
template<class _E>
struct my_enum_item
{
// common section for any "enum_item"
typedef typename _E::type enum_type;
enum_type m_eValue;
LPCTSTR m_szValue;
inline enum_type value() const NO_THROW { return m_eValue; }
inline LPCTSTR str() const NO_THROW { return m_szValue; }
// now I will include an action string
LPCTSTR m_szAction;
inline LPCTSTR action() const NO_THROW { return m_szAction; }
};
template<class _C>
_C action_to_my_enum(const string& __sAction)
{
_C __ret;
while (__sAction.compare(__ret->action()) != 0)
++__ret;
return __ret;
}
DECLARE_ENUM_EX(my_enum, my_enum_item, GREEN = 0, AMBER, RED)
I've also included a function to convert from an action string to an enum instance to show what can be done. In your source code, the implementation will be as follow:
IMPLEMENT_ENUM(my_enum,
ENUM_ITEM(GREEN, _T("go")),
ENUM_ITEM(AMBER, _T("slow down")),
ENUM_ITEM(RED, _T("stop")),
)
Your new enum can be used in the same way as the more simple enum. For instance:
for (my_enum::const_iterator __i = my_enum::begin(); __i != my_enum::end(); ++__i)
std_out << _T("when traffic light changes to ") << __i->str()
<< _T(" you must ") << __i->action();
That's it. If you want to expand the usage of basic_enum look at the flags<> template that I built upon it.