At one point I had looked at implementing a class/template in C++ that would support an Enum that would behave like it does in Ada. It has been some time since I thought about this problem and I was wondering if anyone has ever solved this problem?
EDIT:
My apologies, I should clarify what functionality I thought were useful in the Ada implementation of the Enum. Given the enumeration
type fruit is (apple, banana, cherry, peach, grape);
We know that fruit is one of the listed fruits: apple, banana, cherry, peach, grape. Nothing really different there from C++.
What is very useful are the following pieces of functionality that you get with every enum in Ada without any additional work:
I hope this defines the problem a bit more.
Notes added from comments:
fruit'first
which gives apple
.fruit'last
which gives grape
.fruit'succ(apple)
which gives banana
.fruit'pred(cherry)
which also gives banana
.fruit'pos(cherry)
which returns 2
because Ada uses 0-based enumerations.fruit'val(2)
which returns cherry
.fruit'Image(apple)
which returns the (upper-case) string "APPLE"
.fruit'Value("apple")
which returns the value apple
.See also related SO questions:
Okay, let's leave C++ aside for a moment. C++ is just a superset of C (which means everything that can be done in C can be done in C++ as well). So let's concentrate on plain-C (because that's a language I know well). C has enumerations:
enum fruit { apple, banana, cherry, peach, grape };
This is perfectly legal C and the values are contiguous, and apple has the value zero and banana has the value apple + 1. You can create enumerations with holes, but only if you explicitly make holes like this
enum fruit { apple = 0, banana, cherry = 20, peach, grape };
While apple is 0 and banana is 1, cherry is 20, thus peach is 21 and grape is 22 and everything between 1 and 20 is undefined. Usually you don't want holes. You can do the following:
enum fruit { apple = 0, banana, cherry, peach, grape };
enum fruit myFruit = banana;
myFruit++;
// myFruit is now cherry
printf("My fruit is cherry? %s\n", myFruit == cherry ? "YES" : "NO");
This will print YES. You can also do the following:
enum fruit { apple = 0, banana, cherry = 20, peach, grape };
enum fruit myFruit = banana;
myFruit++;
// myFruit is now cherry
printf("My fruit is cherry? %s\n", myFruit == cherry ? "YES" : "NO");
This will print NO, and the value of myFruit is not the same as any of the enumeration constants.
BTW, to avoid that you must say "enum fruit myFruit", you can avoid the enum with a typedef. Just use "typedef enum fruit fruit;" on an own line. Now you can say "fruit myFruit" without enum in front. It is often done directly when the enum is defined:
typedef enum fruit { apple = 0, banana, cherry, peach, grape } fruit;
fruit myFruit;
Disadvantage is that you don't know anymore that fruit is an enum, it might be an object, a structure or anything else. I usually avoid these type of typedefs, I rather write enum in front if an enum and struct in front if a struct (I will just use them here because it looks nicer).
Getting the string value is not possible. At runtime an enumeration is just a number. That means, it's not possible if you don't know what kind of enumeration that is (as 0 might be apple, but it might also be a different thing of a different enumeration set). However, if you know it is a fruit, then it's easy to write a function that will do it for you. The preprocessor is your friend :-)
typedef enum fruit {
apple = 0,
banana,
cherry,
peach,
grape
} fruit;
#define STR_CASE(x) case x: return #x
const char * enum_fruit_to_string(fruit f) {
switch (f) {
STR_CASE(apple); STR_CASE(banana); STR_CASE(cherry);
STR_CASE(peach); STR_CASE(grape);
}
return NULL;
}
#undef STR_CASE
static void testCall(fruit f) {
// I have no idea what fruit will be passed to me, but I know it is
// a fruit and I want to print the name at runtime
printf("I got called with fruit %s\n", enum_fruit_to_string(f));
}
int main(int argc, char ** argv) {
printf("%s\n", enum_fruit_to_string(banana));
fruit myFruit = cherry;
myFruit++; // myFruit is now peach
printf("%s\n", enum_fruit_to_string(myFruit));
// I can also pass an enumeration to a function
testCall(grape);
return 0;
}
Output:
banana
peach
I got called with fruit grape
This is exactly what you wanted or am I totally on the wrong track here?
One of my colleagues has implemented a tool to generate classes that do most (if not all) of what you want:
http://code.google.com/p/enumgen/
The current implementation is in Lisp, but do not hold that against him :-)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With