有没有C++库来创建强大的枚举?

发布于 2024-08-08 14:33:16 字数 1390 浏览 2 评论 0原文

理想情况下,我希望以下示例能够工作,但我想其中一些示例无法在 C++ 中实现。

{
  typedef StrongEnum<Red=0, Green=1, Blue=2> Color; // not a C++ syntax
  Color c = Color::Red;  // static const 
  Color d;  //error: default constructor 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 ();
}

我经常使用它们,目前我从头开始编写每一个。 我知道完整的通用解决方案是一个梦想,所以我欢迎任何部分解决方案。 也许有人创建了一个库或代码生成器?

更新 1:

问题是相关的。我正在调查哪些问题可以用它们来解决。

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 constructor 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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

奈何桥上唱咆哮 2024-08-15 14:33:16

这就是我的结论:

#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;
}

至少它有一些你想要的行为。这是否缺少您需要的东西?

它使用 g++ 4.3.3 编译,并且似乎工作正常。

我做了命名空间的事情,将枚举放在不同的范围内。 (这样红色就不会被占用等)也许你可以将它剖析成你可以使用的东西? :)

如果你想要 Color::Color 在该命名空间之外,你可以这样做:

typedef Color::Color ColorEnum;

但不幸的是,名称 Color 被命名空间占用了。

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.

握住我的手 2024-08-15 14:33:16

我也讨厌 C++ 中枚举的实际实现。

  • 自动转换为整数类型
  • 没有值检查:执行松散范围检查以查看该值是否适合选择存储它的整数类型
  • 序列化:序列化为 int 很痛苦 > >即使不再使用,您也必须保留旧值,并且只能在最后添加新值
  • 不可能进行迭代,您需要重新定义运算符

我最终推出了自己的模板来尝试自动化,但这并不完全令人满意目前(特别是因为它需要每个枚举的模板专门化,因此不能用于嵌套在类/结构中的枚举:/)

无论如何,我使用的想法是:

  • 一个静态映射来存储值及其“序列化值” ' (在我的例子中,这是一个简单的字符串,因为我不太看重空间并且更喜欢可读性)
  • 要包装的类,它只是在映射中保存一个迭代器,“end”表示未初始化/无效的值。

目前我使用了“真实”枚举,但从你所说的来看,我可能会想到拥有静态实例......尽管它给枚举编写者带来了另一个负担......

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...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文