A C++ Printable Enum
Ever wanted to have enum entries represented or accessible as strings? This is a tool for the job.
A regrettable limitation of C++ enums, is the lack of a printable or string form of the enum entries. Since reflection is not an option (e.g. Java or C#), and manual creation and maintenance of a matching string array is intolerable, the only remaining option is a preprocessor macro. Once such example is a two-pass printable enum presented on codeplex. Below, however, is a one-pass approach I created which I think is more flexable and concise. The macro depends on the boost preprocessor library. The first part is the macro itself:
/*
header description: this is a preprocessor based "printable enum";
Enum entries are created with a corresponding string array, that
can be indexed by the enum entries.
Author: Brent Arias
License: permission is given to use or modify freely, commercially
or otherwise. Please retaint the author name in source code (Brent Arias).
*/
#ifndef PRINTABLE_ENUM
#define PRINTABLE_ENUM
#include <boost/preprocessor/seq/seq.hpp>
#include <boost/preprocessor/seq/enum.hpp>
#include <boost/preprocessor/stringize.hpp>
#include <boost/preprocessor/logical/bitor.hpp>
#include <boost/preprocessor/seq/transform.hpp>
#include <boost/preprocessor/control/iif.hpp>
#include <boost/preprocessor/tuple/eat.hpp>
/***************************************************************
BOOST_PP_EXPR_IIF requires precompiler definition arguments
(viz. PRINTABLE_ENUM_ENUMS, PRINTABLE_ENUM_STRINGS,
PRINTABLE_ENUM_DEBUG) to be either 0 or 1.
This will not build otherwise!!!!
****************************************************************/
/*Usually the ENUM macro should actually expand into an enum,
"define ENUM 1" sets that default*/
//By default, turn enums on
#ifndef PRINTABLE_ENUM_ENUMS
#define PRINTABLE_ENUM_ENUMS 1
#endif
//By default, turn printable strings off
#ifndef PRINTABLE_ENUM_STRINGS
#define PRINTABLE_ENUM_STRINGS 0
#endif
#ifndef PRINTABLE_ENUM_DEBUG
//By default, turn debuggin "compliment" condition off
#define PRINTABLE_ENUM_DEBUG 0
#endif
/*Used internally by the ENUM macro*/
#ifdef ENUM_STR
#undef ENUM_STR
#endif
#define ENUM_STR(r, data, elem) BOOST_PP_STRINGIZE(elem)
/*Make sure there is no space after the '\' line wrap - or you'll
spend hours pursuing "too few arguments" or "too many arguments"
compiler errors.*/
#define ENUM(name, start, entries) \
BOOST_PP_IIF(PRINTABLE_ENUM_ENUMS, \
BOOST_PP_SEQ_ENUM, BOOST_PP_TUPLE_EAT(1)) \
( \
(typedef enum{ BOOST_PP_SEQ_HEAD(entries) = start) \
BOOST_PP_SEQ_TAIL(entries) \
(LAST_##name } name;) \
) \
BOOST_PP_IIF(BOOST_PP_BITOR(PRINTABLE_ENUM_DEBUG,PRINTABLE_ENUM_STRINGS), \
BOOST_PP_SEQ_ENUM, BOOST_PP_TUPLE_EAT(1)) \
( \
(static const char* name##_Str[]={ BOOST_PP_STRINGIZE(BOOST_PP_SEQ_HEAD(entries)) ) \
BOOST_PP_SEQ_TRANSFORM(ENUM_STR, _, BOOST_PP_SEQ_TAIL(entries) ) \
(};) \
)
#endif
With the above macro recorded in its own header file, it can be used as often as needed for enum definitions. Take for example a ‘myEnumDefinition’ that is made up of colors, starting at index ’0′. The macro is then used as follows:
#define PRINTABLE_ENUM_STRINGS 1 #include "PrintableEnum.h" ENUM(myEnumDefinition, 0, (YELLOW) /*enums delimited with parens instead of commas*/ (RED) (GREEN) (BLUE) (MAGENTA) )
The above ENUM macro expansion:
- creates the “myEnumDefinition” typedef
- starts the enumeration at zero
- creates the actual enum values (e.g. GREEN, BLUE, etc)
- creates the string array “myEnumDefinition_Str[]‘
- fills the string array with values such as “GREEN”, “BLUE”, etc
- creates a “tail” enum value called “LAST_myEnumDefinition”
Just remember that the string array for the enum bears the same name as the enum, but appended with “_Str”. That’s it!



