c++creflectionenums

C/C++: any way to get reflective enums?


I've encountered this situation so many times...

 enum Fruit {
  Apple,
  Banana,
  Pear,
  Tomato
 };

Now I have Fruit f; // banana and I want to go from f to the string "Banana"; or I have string s = "Banana" and from that I want to go to Banana // enum value or int.

So far I've been doing this.. Assuming the enum is in Fruit.h:

// Fruit.cpp
const char *Fruits[] = {
 "Apple",
 "Banana",
 "Pear",
 "Tomato",
 NULL
};

Obviously that's a messy solution. If a developer adds a new fruit to the header and doesn't add a new entry in Fruits[] (can't blame him, they have to be in two different files!) the application goes boom.

Is there a simple way to do what I want, where everything is in one file? Preprocessor hacks, alien magic, anything..

PS: This, contrary to reflection "for everything", would be really trivial to implement in compilers. Seeing how common a problem it is (at least for me) I really can't believe there is no reflective enum Fruit.. Not even in C++0x.

PS2: I'm using C++ but I tagged this question as C as well because C has the same problem. If your solution includes C++ only things, that's ok for me.


Solution

  • This one requires the fruits to be defined in an external file. This would be the content of fruit.cpp:

    #define FRUIT(name) name
    enum Fruit {
    #include "fruit-defs.h"
    NUM_FRUITS
    };
    #undef FRUIT
    #define FRUIT(name) #name
    const char *Fruits [] = {
    #include "fruit-defs.h"
    NULL
    };
    #undef FRUIT
    

    And this would be fruit-defs.h:

    FRUIT(Banana),
    FRUIT(Apple),
    FRUIT(Pear),
    FRUIT(Tomato),
    

    It works as long as the values start in 0 and are consecutive...

    Update: mix this solution with the one from Richard Pennington using C99 if you need non-consecutive values. Ie, something like:

    // This would be in fruit-defs.h
    FRUIT(Banana, 7)
    ...
    // This one for the enum
    #define FRUIT(name, number) name = number
    ....
    // This one for the char *[]
    #define FRUIT(name, number) [number] = #name