10

我正在用 C++ 制作一个枚举,以使用二进制标志制作一个有限状态机。看起来像:

enum VStates
{
    NEUTRAL         =   0x00000000,     // 000000
    //  Physical Status
    DRY             =   0x00000001,     // 000001
    WET             =   0x00000002,     // 000010
    HOT             =   0x00000004,     // 000100
    COLD            =   0x00000008,     // 001000
    BURNED          =   0x00000016,     // etc..
    FROZEN          =   0x00000032,
    EROS            =   0x00000064,     // 
    THANATOS        =   0x00000128,     // 
    SLEEP           =   0x00000256,
    STUNNED         =   0x00000512,
    PARALYZED       =   0x00001024,
    POISONED        =   0x00002048,     //
    BLIND           =   0x00004096,
    SOFT            =   0x00008192,     // Flexible
    TOUGH           =   0x00016384,     // Resistent
    MAGNETIZED      =   0x00032768,
    POSSEDERUNT     =   0x00131072,     //
    // Mental Status
    ANGRY           =   0x00262144,
    DRUGGED         =   0x00524288, // Drugs Meaning
    HORNY           =   0x01048576, // Sexual Meaning
    // Material Status
    METAL           =   0x02097152,
    WOOD            =   0x04194304,
    GLASS           =   0x08388608,
    AIR             =   0x16777216,
    EARTH           =   0x33554432,
    DUST            =   0x67108864,
    LIGHT           =   0x134217728,
    SHADOW          =   0x268435456,
    WATER           =   0x536870912,
    // Total Status
    PROTECTED       =   0x1073741824,
    INVULNERABLE    =   0x2147483648

};

有些状态是不兼容的,所以我使用按位运算符来管理它们。现在,我的编译器说:

warning: integer constant is too large for 'long' type

这是声明此枚举的正确方法吗?我喜欢避免警告,我该如何解决这个问题?

4

5 回答 5

13

在 C++11 中,您可以指定枚举的基础类型。

#include <cstdint>

enum VStates : uint64_t {
    // Values
}

在旁注中,我建议不要计算所有这些 2 的幂。您通过写入一个十六进制常量但给它一个以 10 为基数的数字,从而在计算中出错。但是,我建议不要重新计算所有这些,而是​​建议:

#include <cstdint>

enum VStates : uint64_t {
    NEUTRAL = 0ULL,
    DRY = 1ULL << 0,
    WET = 1ULL << 1,
    HOT = 1ULL << 2,
    COLD = 1ULL << 3,
    // etc.
}

那你肯定不会犯错。ULL后缀确保文字被接受为至少 64 位宽的整数。

于 2012-11-14T19:24:40.450 回答
11

(注意:为了使我的答案完整,我将添加一些我没有花时间注意到但其他人指出的内容:您使用的是0x前缀,这意味着您的数字将被解释为十六进制。他们实际上并没有是 2 的幂,而您的 bitflag 测试将无法正常工作!)

如果您的枚举像这样失控,请不要使用枚举类型。使用类似std::bitset. 那么你的枚举可以只是一个简单的编号列表,用于表示集合中位的位置......而且你不会以指数方式耗尽你的枚举空间!

例如:

enum VState {
    NEUTRAL,
    DRY,
    WET,
    COLD,
    BURNED,
    FROZEN,
    /* ... */
    VState_Max
};

bitset<VState_Max> state;

state[COLD] = true;
if (state[COLD]) {
    cout << "I am cold\n";
}

现在你的枚举只是很小的、可维护的数字,你不必担心在 64 位平台上或诸如此类的东西。

我注意到您在原始示例中为 NEUTRAL 提供了“0”值。如果您的意图是可以将它与其他东西结合使用......例如能够state = NEUTRAL | INVULNERABLE | SHADOW单独测试NEUTRAL,那以前是行不通的。现在它将...您只需将其保留在用于索引位集的枚举中。

但是,如果它打算作为“nothing set”的名称,那么您将从枚举中删除它,而是测试没有设置的位:

if (state.none()) {
    // we are in the "NEUTRAL" state of nothing set...
}

...如果您想将所有位设置为 false,您可以选择:

state.reset();
于 2012-11-14T19:26:34.787 回答
4

枚举有 31 个非零值,因此它们都可以放入 32 位无符号值。问题是这里的值不是位值。要么写成十进制值(去掉0x前面的),要么写成十六进制值(0x01、0x02、0x04、0x08、0x10、0x20、0x40等)我个人不喜欢,但有些人写这个带班次的常数:1<<0, 1<<1, 1<<2, 1<<3, etc.

于 2012-11-14T19:25:59.980 回答
3

如果您使用的是 C++11,则可以将具有定义类型的强类型枚举声明为unsigned long long_int64在 Windows 中,尽管您可能应该使用可移植的uint64_t),前提是这将您的范围扩展得足够远。

感谢 Joachim 提供 C++11 枚举使用示例的链接:Strongly Typed Enums

于 2012-11-14T19:21:50.103 回答
0

使用较小的数字。枚举只能和 long 一样大。long 的大小取决于编译器,但典型的大小是 32 位或 64 位。我在那里看到一些 10 位的十六进制数字,它们太大了。

于 2012-11-14T19:21:47.463 回答