开发者

Is there C++ library to create strong Enums?

Ideally I would like a following examples to work, but I guess some of it is not implementable in C++.

{
  typedef StrongEnum<Red=0, Green=1, Blue=2> Color; // not a C++ syntax
  Color c = Color::Red;  // static const 
  Color d;  //error: default c开发者_开发知识库onstructor is private 
  Color d = c;
  Color e = Color::OfInt(5); // ifdef DEBUG - Runtime error: Enum out of range 

  int sum = 0;

  // I do have these macros, but separate for each enum - FOREACH_COLOR(c)
  FOREACH_ENUM (Color c) { 
    sum += c.ToInt ();
  }

  ArrayMap<Color, string> map;  // Internally this is const size array, possible
  map [Color::Red] = "red";     // because Color have static const Limit = 3 inisde. 

  // Advanced: EnumPair does bitpacking.
  // currently I implement it manually for every pair of Enum's I need.
  typedef EnumPair <door=Color, window=Color> ColorPair; // I guess I can't get this, can I?
  ColorPair pair (door = Color::Red, window = Color::Green); // I guess I can't give the labels here or one line above, can I?
  Color w = pair.window;
  Color w = pair.window ();
}

I use them a lot and currently I I write each one from the scratch. I am aware that a complete generic solution is a dream, so I welcome any partial solutions. Maybe somebody created a library or a code generator?

Update 1:

This and this questions are related. I'm investigating which issues can be solved with them.


This is what I figured out:

#include <cstdio>
#include <string>
#include <map>

namespace Color
{
    typedef enum
    {
        Red = 0,
        Green = 1,
        Blue = 2
    } Color;

    Color colors[] = {Red, Green, Blue}; // same order as above,
                                         //to preserve index.

    //int colors_len = sizeof(colors)/sizeof(Color);
    // (if you want to check for valid values)

    static inline Color OfInt(int value)
    {
        // if(value >= colors_len) do error thing;
        return colors[value];
    }
}

int main()
{
    Color::Color c = Color::Red;

    printf("%d,", c);

    c = Color::OfInt(1);

    printf("%d,", c);

    c = Color::Blue;

    printf("%d\n", c);

    std::map<Color::Color, std::string> map;

    map[Color::Red] = "red";

    return 0;
}

Atleast it has some of the behaviour you wanted. Does this lack something that you need?

It compiles with g++ 4.3.3, and seems to work ok.

I did the namespace thing to put the enums under a different scope. (so that Red's not taken etc.) Maybe you can dissect it into something you could use? :)

If you want Color::Color outside that namespace, you could do:

typedef Color::Color ColorEnum;

But the name Color is unfortunately occupied by the namespace.


I also loathe the actual implementation of enums in C++.

  • Automatic conversions to integral types
  • No value checking: a loose range checking is performed to see if the value fit in the integral type chosen to store it
  • Serialization: serialized as int is painful > you have to keep old values even if not used any longer and you have to add new values at the end only
  • No iteration possible, you need to redefine the operators

I ended up rolling my own template to try and automate, but it's not completely satisfying at the moment (especially because it requires template specialization for each enum, and so cannot be used for enums nested in a class / struct :/)

Anyway, the idea I used was:

  • A static map to store the values and their 'serialization value' (which in my case is a simple string because I don't value space so much and prefer readability)
  • A class to wrap, which simply holds an iterator in the map, 'end' representing a not-initialized/invalid value.

For the moment I used the 'true' enum, but from what you said I might think of having static instances... though it puts yet another burden on the enum writer...

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜