Используйте препроцессор:
#define VISIT_ERROR(FIRST, MIDDLE, LAST) \
FIRST(ErrorA) MIDDLE(ErrorB) /* MIDDLE(ErrorB2) */ LAST(ErrorC)
enum Errors
{
#define ENUMFIRST_ERROR(E) E=0,
#define ENUMMIDDLE_ERROR(E) E,
#define ENUMLAST_ERROR(E) E
VISIT_ERROR(ENUMFIRST_ERROR, ENUMMIDDLE_ERROR, ENUMLAST_ERROR)
// you might undefine the 3 macros defined above
};
std::string toString(Error e)
{
switch(e)
{
#define CASERETURN_ERROR(E) case E: return #E;
VISIT_ERROR(CASERETURN_ERROR, CASERETURN_ERROR, CASERETURN_ERROR)
// you might undefine the above macro.
// note that this will produce compile-time error for synonyms in enum;
// handle those, if you have any, in a distinct macro
default:
throw my_favourite_exception();
}
}
Преимущество этого подхода заключается в том, что:
- это все еще легко понять, но
- допускает различные посещения (не только струны)
Если вы хотите отказаться от первого, создайте себе макрос FOREACH (), затем #define ERROR_VALUES() (ErrorA, ErrorB, ErrorC)
и напишите своим посетителям в терминах FOREACH (). Тогда попробуйте пройти проверку кода:).