C++ Enum to String Macro (without enum Forward Declaration)

I briefly talked about Enums and Serializing Enums by value Here.

Now I will show you the macro I use in C/C++ when enum forward declaration isn't possible.

In a file labeled something like EnumToString.h write something like this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
#include <string.h>

#undef ENUM_BEGIN
#undef ENUM
#undef ENUM_END
#define ENUM_BEGIN(typ)\
	const char* typ##_Names[]= {
#define ENUM(nam) #nam
#define ENUM_END(typ)\
	 };\
	const char *typ##_ToString(typ value) { return typ##_Names[value]; }\
	bool typ##_FromString(const char* value, typ &o_OutValue) {\
		for(int index=0; index < sizeof(typ##_Names)/ sizeof(typ##_Names[0]); ++index) {\
			if(strcmp(value,typ##_Names[index])==0) {\
				o_OutValue = (typ)index; \
				return true;\
			}\
		}\
		return false; /*Enum value not found*/\
	}

And in a file labeled something like EnumMacro.h you'll need to write this:

1
2
3
4
5
6
7
8
#define ENUM_BEGIN(typ)\
    enum typ {
#define ENUM(nam) nam
#define ENUM_END(typ)\
    }; \
    const char* typ##_ToString(type value); \
    bool typ##_FromString(const char* value, typ &o_OutValue);
    

Now lets see how this works in an example.  Lets say we declare an Enum in a ColorEnums.h.  Unfortunately without enum forward declaration we need to seperate the enums to their own .h file.  The good news is you can declare multiple enums at once in the .h so grouping the enums by system works well to reduce file count. When we do this we need to use the macro to make this work:

ColorEnums.h:

1
2
3
4
5
ENUM_BEGIN(ColorEnum)
    ENUM(RED),
    ENUM(BLUE),
    ENUM(GREEN)
ENUM_END(ColorEnum)

Now in Colors.cpp we need to do this:

1
2
#include "EnumMacro.h"
#include "Colors.h"

And in a single cpp file, something like EnumToString.cpp we need to do this:

1
2
3
4
5
6
7
8
9
#include "EnumMacro.h"

#include "ColorEnums.h"
//along with any other enum.h files you want

#include "EnumToString.h"

#include "ColorEnums.h"
//Same .h file list as above

What this will do is in the EnumToString.cpp it will compile the following functions:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
enum ColorEnum {
   RED,
   BLUE,
   GREEN
};
const char* ColorEnum_ToString(ColorEnum value);
bool ColorEnum_FromString(const char* value, ColorEnum &o_OutValue);

const char* ColorEnum_Names[] = {
    "RED",
    "BLUE",
    "GREEN"
};
const char* ColorEnum_ToString(Colors value)
{ return ColorEnum_ToString[value]; }
bool ColorEnum_FromString(const char* value, typ &o_OutValue)
{
    for(int index=0;
         index < sizeof(ColorEnum_Names)/sizeof(ColorEnum_Names[0]); 
        index++) 
    {
        if(strcmp(value, ColorEnum_Names[index]) == 0) {
            o_OutValue = (ColorEnum)index;
            return true;
        }
    }
    return false;
}

One draw back to this method is it only supports default value enums.  So this will not work for enums used as masks (unless their use in code is something like 1<<ENUM_VALUE) or with specific values (which I argue is not a correct usage of enums).  Hopefully this will help getting the enum names in C and C++ for you for most cases.