代码之家  ›  专栏  ›  技术社区  ›  SadSido

是否有任何已知的迭代枚举值的范例?

  •  12
  • SadSido  · 技术社区  · 17 年前

    我有一些C++代码,其中声明了以下枚举:

    enum Some 
    {
       Some_Alpha = 0,
       Some_Beta,
       Some_Gamma,
       Some_Total
    };
    int array[Some_Total];
    

    alpha、beta和gamma的值是连续的,我很乐意使用以下循环迭代它们:

    for ( int someNo = (int)Some_Alpha; someNo < (int)Some_Total; ++someNo ) {}
    

    这个循环是正常的,直到我决定改变枚举中声明的顺序,比如,使beta成为第一个值,alpha成为第二个值。这会使循环头无效,因为现在我必须从beta迭代到total。 那么,遍历枚举的最佳实践是什么?我希望在不每次更改循环头的情况下迭代所有值。我可以想到一个解决方案:

    enum Some 
    {
       Some_Start = -1,
       Some_Alpha,
       ...
       Some_Total
    };
    int array[Some_Total];
    

    从(start+1)迭代到total,但它看起来很难看,而且我从未在代码中看到过有人这样做。是否有任何已知的迭代枚举的范例,或者我只需要确定枚举值的顺序?(假设一下,我确实有一些很棒的理由来改变枚举值的顺序)……

    7 回复  |  直到 12 年前
        1
  •  0
  •   Dewfy    15 年前
    enum Some
    {
       Some_first_ = 0,
       Some_Alpha = Some_first_,
    ....
       Some_last_
    };
    

    这样,您可以授予“第一个”和“最后一个”从不更改订单。

        2
  •  13
  •   sbi    17 年前

    您可以定义 operator++() 为了你 enum . 这样做的好处是它使用了众所周知的标准递增操作符范式。 :)

    根据您的枚举是否是连续的,您可以将其视为 int 或者使用开关:

    Some& operator++(Some& obj)
    {
    # if YOUR_ENUMS_ARE_CONTIGUOUS
      int i = obj;
      if( ++i > Some_Total ) i = Some_Alpha;
      return obj = static_cast<Some>(i);
    # else 
      switch(obj)
      {
        case Some_Alpha : obj = Some_Beta;  break;
        case Some_Beta  : obj = Some_Gamma; break;
        case Some_Gamma : obj = Some_Total; break;
        case Some_Total : obj = Some_Alpha; break;
        default: assert(false); // changed enum but forgot to change operator
      }
      return obj;
    # endif
    }
    

    注意,如果 运算符+ +() 是定义的,用户可能希望 operator--() 也是。

        3
  •  4
  •   anon    17 年前

    不,没有办法做到这一点,因为不能保证有人没有写这样的代码:

    enum Some 
    {
       Some_Alpha = 0,
       Some_Beta,
       Some_Gamma = 42,
       Some_Delta, 
      Some_Total
    };
    
        4
  •  3
  •   Zed    17 年前

    你可以看看这个 article 用它 source code 关于如何用静态类成员实现这一点。

        5
  •  1
  •   Community Mohan Dere    9 年前

    在C++ 11中(可能更早),您可以使用下面的HACK Some 可迭代的:

    Some operator++(Some& s) {
        return s = (Some )(std::underlying_type<Some>::type(x) + 1); 
    }
    Some operator*(Some s) {
        return s;
    } 
    Some begin(Some s) {
        return Some_Alpha;
    
    Some end(Some s) {
        return Some_Gamma;
    }
    
    int main() { 
        // the parenthesis here instantiate the enum
        for(const auto& s : Some()) { 
            // etc. etc.
        }
        return 0;
    }
    

    (这个答案不知羞耻地改编自 here 。)

        6
  •  0
  •   Sean A.O. Harney    17 年前

    如果不使用任何赋值,则保证枚举是以0开头的顺序。 是的。

    您可以做的最好的事情是将它们保持在枚举定义中所需的顺序中,并使用for循环在它们之间循环。

        7
  •  0
  •   graham.reeds    17 年前

    我将所有枚举放在它们自己的名称空间中。例子:

    namespace Foo {
    enum Enum {
        First=0, // must be sequential
        Second,
        Third,
        End // must be last
    };
    }
    

    在代码中:

    for (int i=Foo::First; i!=Foo::End; i++) {
    // do stuff
    }
    

    这是因为C++允许这样的东西(没有在编译器中测试):

    enum Foo {
    Alpha = 1
    };
    
    enum Bar {
    Beta = 2
    };
    
    Foo foo = Beta;
    

    这显然是错误的。