The technique from Making something both a C identifier and a string? can be used here.
As usual with such preprocessor stuff, writing and understanding the preprocessor part can be hard, and includes passing macros to other macros and involves using # and ## operators, but using it is real easy. I find this style very useful for long enums, where maintaining the same list twice can be really troublesome.
Factory code - typed only once, usually hidden in the header:
enumFactory.h:
// expansion macro for enum value definition
#define ENUM_VALUE(name,assign) name assign,
// expansion macro for enum to string conversion
#define ENUM_CASE(name,assign) case name: return #name;
// expansion macro for string to enum conversion
#define ENUM_STRCMP(name,assign) if (!strcmp(str,#name)) return name;
/// declare the access function and define enum values
#define DECLARE_ENUM(EnumType,ENUM_DEF)
enum EnumType {
ENUM_DEF(ENUM_VALUE)
};
const char *GetString(EnumType dummy);
EnumType Get##EnumType##Value(const char *string);
/// define the access function names
#define DEFINE_ENUM(EnumType,ENUM_DEF)
const char *GetString(EnumType value)
{
switch(value)
{
ENUM_DEF(ENUM_CASE)
default: return ""; /* handle input error */
}
}
EnumType Get##EnumType##Value(const char *str)
{
ENUM_DEF(ENUM_STRCMP)
return (EnumType)0; /* handle input error */
}
Factory used
someEnum.h:
#include "enumFactory.h"
#define SOME_ENUM(XX)
XX(FirstValue,)
XX(SecondValue,)
XX(SomeOtherValue,=50)
XX(OneMoreValue,=100)
DECLARE_ENUM(SomeEnum,SOME_ENUM)
someEnum.cpp:
#include "someEnum.h"
DEFINE_ENUM(SomeEnum,SOME_ENUM)
The technique can be easily extended so that XX macros accepts more arguments, and you can also have prepared more macros to substitute for XX for different needs, similar to the three I have provided in this sample.
Comparison to X-Macros using #include / #define / #undef
While this is similar to X-Macros others have mentioned, I think this solution is more elegant in that it does not require #undefing anything, which allows you to hide more of the complicated stuff is in the factory the header file - the header file is something you are not touching at all when you need to define a new enum, therefore new enum definition is a lot shorter and cleaner.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…