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

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


当前回答

c++没有自省,所以你不能在运行时确定这类事情。

其他回答

典型的方式如下:

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值。

您可以尝试并定义以下宏:

#define for_range(_type, _param, _A1, _B1) for (bool _ok = true; _ok;)\
for (_type _start = _A1, _finish = _B1; _ok;)\
    for (int _step = 2*(((int)_finish)>(int)_start)-1;_ok;)\
         for (_type _param = _start; _ok ; \
 (_param != _finish ? \
           _param = static_cast<_type>(((int)_param)+_step) : _ok = false))

现在你可以使用它:

enum Count { zero, one, two, three }; 

    for_range (Count, c, zero, three)
    {
        cout << "forward: " << c << endl;
    }

它可以用来在无符号、整数、枚举和字符之间来回迭代:

for_range (unsigned, i, 10,0)
{
    cout << "backwards i: " << i << endl;
}


for_range (char, c, 'z','a')
{
    cout << c << endl;
}

尽管它的定义很尴尬,但它优化得很好。我看了一下vc++中的反汇编程序。 代码非常高效。不要推迟,但是三个for语句:编译器在优化后只会产生一个循环!你甚至可以定义封闭的循环:

unsigned p[4][5];

for_range (Count, i, zero,three)
    for_range(unsigned int, j, 4, 0)
    {   
        p[i][j] = static_cast<unsigned>(i)+j;
    }

显然,不能在有间隙的枚举类型中进行迭代。

(把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等)。如果你想指定枚举成员的值而不是默认值,同样不起作用。

其他答案中没有涉及到的东西=如果你使用强类型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)

}

枚举就不行。也许枚举不是最适合您的情况。

一个常见的约定是将最后一个枚举值命名为MAX,并使用它来控制一个int类型的循环。