This is an extension of the following question which already has great answers.
However, in all answers where the expansion is carried out by the pre-processor the enums are declared in a special way under the same project. But what if the header file that declares these enums is not your own or the enums are declared out of id order.
In my case, I have an SDK that I'm using where large tables of enums are already declared in a separate header file like the following:
#define NODE_GRAPH_TYPE(_name, _enum) _name = _enum,
enum NodeGraphType
{
// next available ID value is 7
NODE_GRAPH_TYPE(GT_UNKNOWN , 0)
NODE_GRAPH_TYPE(GT_STANDARD , 1)
NODE_GRAPH_TYPE(GT_APP_SETTINGS , 3)
NODE_GRAPH_TYPE(GT_GEOMETRYARCHIVE , 2)
NODE_GRAPH_TYPE(GT_SCRIPTED , 5)
NODE_GRAPH_TYPE(GT_SCRIPT_STORAGE , 6)
NODE_GRAPH_TYPE(GT_PROJECT_SETTINGS , 4)
};
What I want to do is to try to avoid is this type of thing:
function NODE_GRAPH_NAME(int type)
{
switch(type)
{
case: GT_PROJECT_SETTINGS:
return "GT_PROJECT_SETTINGS";
// ...
};
}
or
static const char* NODE_GRAPH_NAME[] = {
"GT_UNKNOWN",
/// ...
}
The best I've come up with this this so far:
#define STRINGIFY(_x) #_x
static const char* NODE_GRAPH_NAME[] = {
STRINGIFY(GT_UNKNOWN),
STRINGIFY(GT_STANDARD),
STRINGIFY(GT_GEOMETRYARCHIVE),
STRINGIFY(GT_APP_SETTINGS)
// etc
};
But it still requires me to duplicate all the tables of enums and not only that, but them in order and double check there are no holes.
Is there perhaps a more elegant and automated way to go about this? If it helps, I'm actually compiling this under C++. But the library I'm linking to is pure C. So you could do something fancy with templates perhaps.
Based on Thomas Matthews answer below, this is what I came up with the following:
Which isn't entirely automatic, but isn't too difficult to work with. In redefining NODE_GRAPH_TYPE I can copy verbatim the table from the SDK header and place it into the NODE_GRAPH_TYPES table definition. And it works. Then I can create a lookup function to locate the item I require. The nice thing about this is that holes don't matter and neither do out of order definitions.
#undef NODE_GRAPH_TYPE
#define NODE_GRAPH_TYPE(_name, _enum) { _enum, #_name },
static const Enum_Entry NODE_GRAPH_TYPES[] =
{
NODE_GRAPH_TYPE(GT_UNKNOWN , 0)
NODE_GRAPH_TYPE(GT_STANDARD , 1)
NODE_GRAPH_TYPE(GT_APP_SETTINGS , 3)
NODE_GRAPH_TYPE(GT_GEOMETRYARCHIVE , 2)
NODE_GRAPH_TYPE(GT_SCRIPTED , 5)
NODE_GRAPH_TYPE(GT_SCRIPT_STORAGE , 6)
NODE_GRAPH_TYPE(GT_PROJECT_SETTINGS , 4)
};
static const unsigned int NODE_GRAPH_TYPES_COUNT =
sizeof(NODE_GRAPH_TYPES) / sizeof(NODE_GRAPH_TYPES[0]);
const char* NODE_GRAPH_TYPE_NAME(int id)
{
for (int i = 0; i < NODE_GRAPH_TYPES_COUNT; ++i){
if (PIN_TYPES[i].enum_value == id)
return PIN_TYPES[i].enum_text;
}
return "Unknown";
}