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

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


当前回答

这些解决方案太复杂了,我喜欢这样:

enum NodePosition { Primary = 0, Secondary = 1, Tertiary = 2, Quaternary = 3};

const NodePosition NodePositionVector[] = { Primary, Secondary, Tertiary, Quaternary };

for (NodePosition pos : NodePositionVector) {
...
}

其他回答

在评论中已经有关于std::initializer_list (c++ 11)的讨论。 我提到example是为了遍历枚举。

或者std::initializer_list和一个更简单的语法:

enum E {
    E1 = 4,
    E2 = 8,
    // ..
    En
};

constexpr std::initializer_list<E> all_E = {E1, E2, /*..*/ En};

然后

for (auto e : all_E) {
    // Do job with e
}

参考链接

在c++11中,实际上有一个替代方案:编写一个模板化的自定义迭代器。

让我们假设枚举是

enum class foo {
  one,
  two,
  three
};

这段泛型代码将会非常有效地达到目的——放置在泛型头文件中,它将为你提供任何你可能需要迭代的枚举:

#include <type_traits>
template < typename C, C beginVal, C endVal>
class Iterator {
  typedef typename std::underlying_type<C>::type val_t;
  int val;
public:
  Iterator(const C & f) : val(static_cast<val_t>(f)) {}
  Iterator() : val(static_cast<val_t>(beginVal)) {}
  Iterator operator++() {
    ++val;
    return *this;
  }
  C operator*() { return static_cast<C>(val); }
  Iterator begin() { return *this; } //default ctor is good
  Iterator end() {
      static const Iterator endIter=++Iterator(endVal); // cache it
      return endIter;
  }
  bool operator!=(const Iterator& i) { return val != i.val; }
};

你需要专门化它

typedef Iterator<foo, foo::one, foo::three> fooIterator;

然后你可以使用range-for进行迭代

for (foo i : fooIterator() ) { //notice the parentheses!
   do_stuff(i);
}

枚举中没有空白的假设仍然成立;没有假设实际需要多少位来存储枚举值(感谢std::underlying_type)

将变量强制转换为int&类型可以在保持类型可读的同时进行递增。

#include <iostream>

enum MyEnum
{
    ONE,
    TWO,
    THREE,
    FOUR,
};

int main()
{
    for (MyEnum v = MyEnum::ONE; v <= MyEnum::FOUR; ++(int&)v)
    {
        std::cout<<v<<std::endl;
    }

    return 0;
}
0
1
2
3

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

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

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