我只是注意到不能在枚举上使用标准数学运算符,如++或+=。

那么,在c++枚举中遍历所有值的最佳方法是什么?


当前回答

大多数解决方案基于(MIN, MAX)范围内的循环,但忽略了枚举中可能存在漏洞的事实。

我的建议是:

        for (int i = MYTYPE_MIN; i <= MYTYPE_MAX; i++) {
            if (MYTYPE_IsValid(i)) {
                MYTYPE value = (MYTYPE)i;
                // DoStuff(value)
            }   
        }   
        

其他回答

只需创建一个int型数组并遍历该数组,但使最后一个元素为-1并使用它作为退出条件。

enum为:

enum MyEnumType{Hay=12,Grass=42,Beer=39};

然后创建数组:

int Array[] = {Hay,Grass,Beer,-1};

for (int h = 0; Array[h] != -1; h++){
  doStuff( (MyEnumType) Array[h] );
}

当然,只要-1检查不与任何一个元素冲突,无论表示中的整数都不会被分解。

典型的方式如下:

enum Foo {
  One,
  Two,
  Three,
  Last
};

for ( int fooInt = One; fooInt != Last; fooInt++ )
{
   Foo foo = static_cast<Foo>(fooInt);
   // ...
}

请注意,枚举Last将被迭代跳过。利用这个“假的”Last enum,你不必每次想要添加一个新enum时都将for循环中的终止条件更新为最后一个“真实的”enum。 如果你以后想添加更多的枚举,只要在Last之前添加它们。本例中的循环仍然有效。

当然,如果指定了enum值,则会中断:

enum Foo {
  One = 1,
  Two = 9,
  Three = 4,
  Last
};

这说明枚举并不是真正用于遍历的。处理枚举的典型方法是在switch语句中使用它。

switch ( foo )
{
    case One:
        // ..
        break;
    case Two:  // intentional fall-through
    case Three:
        // ..
        break;
    case Four:
        // ..
        break;
     default:
        assert( ! "Invalid Foo enum value" );
        break;
}

如果你真的想要枚举,把枚举值填充到一个向量中,然后遍历它。这也将正确地处理指定的enum值。

假设枚举是按顺序编号是容易出错的。此外,您可能只希望迭代选定的枚举数。如果这个子集很小,显式遍历它可能是一个优雅的选择:

enum Item { Man, Wolf, Goat, Cabbage }; // or enum class

for (auto item : {Wolf, Goat, Cabbage}) { // or Item::Wolf, ...
    // ...
}

其他答案中没有涉及到的东西=如果你使用强类型c++ 11枚举,你不能对它们使用++或+ int。在这种情况下,需要一个有点混乱的解决方案:

enum class myenumtype {
  MYENUM_FIRST,
  MYENUM_OTHER,
  MYENUM_LAST
}

for(myenumtype myenum = myenumtype::MYENUM_FIRST;
    myenum != myenumtype::MYENUM_LAST;
    myenum = static_cast<myenumtype>(static_cast<int>(myenum) + 1)) {

  do_whatever(myenum)

}

(把Marski的回答当作一个很大的暗示……)

由于枚举定义的主体与初始化列表相同,如果我们使用一个简单的宏来写出值,就可以在不重复项目列表的情况下做到这一点:

#define ITEM_LIST_MACRO Wolf, Goat, Cabbage

enum Item { ITEM_LIST_MACRO }; // Define the enum

// Now iterate through it
for (auto item : { ITEM_LIST_MACRO }) {
}

优点:简单,没有重复,不需要保持恼人的第一个/最后一个哨兵值。(事实上,我认为这可能是目前为止建议的唯一解决方案,不需要用户记得在新项目添加到列表时更新“结束”标记。)

缺点:不适用于范围限定的枚举(enum类),因为初始化列表需要范围(Item::Wolf等)。如果你想指定枚举成员的值而不是默认值,同样不起作用。