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

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


当前回答

只需创建一个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 Item { Man, Wolf, Goat, Cabbage }; // or enum class

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

使用lambda,我发现这是遍历枚举的最佳(现代)方式。 这大大提高了抽象性。 甚至可以使它成为模板,所以它适用于任何枚举。 这段代码不会给您带来clang(-tidy)问题。

#include <functional>

/// @brief Loop over all enum values where the last enum value is the invalid one
void forEachAction(std::function<void(Enum)> &&doThis) {
    for (int value = 0; value = static_cast<int>(Enum::LastValue); ++value ) {
        doThis(static_cast<Enum>(value ));
    }
}

...

forEachAction([this](Enum value) {
    ...  // what you want to execute for every enum
});

还可以重载枚举类型的自增/自减操作符。

我经常这样做

    enum EMyEnum
    {
        E_First,
        E_Orange = E_First,
        E_Green,
        E_White,
        E_Blue,
        E_Last
    }

    for (EMyEnum i = E_First; i < E_Last; i = EMyEnum(i + 1))
    {}

或者如果不是连续的,但有规则步长(例如位标志)

    enum EAnimalCaps
    {
        E_None    = 0,
        E_First   = 0x1,
        E_CanFly  = E_First,
        E_CanWalk = 0x2
        E_CanSwim = 0x4,
        E_Last
    }
    
    class MyAnimal
    {
       EAnimalCaps m_Caps;
    }

    class Frog
    {
        Frog() : 
            m_Caps(EAnimalCaps(E_CanWalk | E_CanSwim))
        {}
    }

    for (EAnimalCaps= E_First; i < E_Last; i = EAnimalCaps(i << 1))
    {}
enum class A {
    a0=0, a3=3, a4=4
};
constexpr std::array<A, 3> ALL_A {A::a0, A::a3, A::a4}; // constexpr is important here

for(A a: ALL_A) {
  if(a==A::a0 || a==A::a4) std::cout << static_cast<int>(a);
}

constexpr std::array甚至可以迭代非顺序的枚举,而无需编译器实例化数组。这取决于编译器的优化启发式以及是否取数组的地址。

In my experiments, I found that g++ 9.1 with -O3 will optimize away the above array if there are 2 non-sequential values or quite a few sequential values (I tested up to 6). But it only does this if you have an if statement. (I tried a statement that compared an integer value greater than all the elements in a sequential array and it inlined the iteration despite none being excluded, but when I left out the if statement, the values were put in memory.) It also inlined 5 values from a non-sequential enum in [one case|https://godbolt.org/z/XuGtoc]. I suspect this odd behavior is due to deep heuristics having to do with caches and branch prediction.

这里有一个godbolt的简单测试迭代的链接,演示了数组并不总是被实例化。

这种技术的代价是写入enum元素两次,并保持两个列表同步。