在C++中迭代连续枚举值的最简方法

16

在C++中,迭代枚举值的首选简单方法是什么?我在之前的SO问题中发现了涉及创建自定义operator++等内容的问题,但这似乎有些过度。到目前为止,我想出的最好方法是:

enum {
   FOO,
   BAR,
   BLECH,
   NUM_ENUMS
} MyEnum;

//for (MyEnum m = FOO; m < NUM_ENUMS; ++m)             // compile error
//    ...

//for (MyEnum m = FOO; m < NUM_ENUMS; m = m + 1)       // compile error
//    ...

for (MyEnum m = FOO; m < NUM_ENUMS; m = MyEnum(m + 1)) // OK ?
    ...

从编码风格的角度来看,这是否合理,并且是否可能会生成警告(g++ -Wall ... 看起来对此很满意)?


5
也许一个副问题是为什么您想要枚举迭代,如果您确实需要,有没有更好的方法来表示命名值以进行迭代?考虑使用std :: map容器。 - woosah
2
只要您不定义元素的自定义值并在它们之间留空格(例如:FOO = 1,BAR = 5,BLECH = 7),那么这很好。 - dunadar
1
你的第三次尝试应该没问题了(参见这个答案 - Christian Ammer
1
我一直在思考如何迭代枚举:在循环和值一致性中使用枚举 - PaperBirdMaster
1
有一个库Better Enums提供了你所需要的功能。它还允许将枚举解释为字符串,以及许多其他功能。开发人员声称它可能会成为C++17特性集的一部分。 - ZeroPhase
显示剩余2条评论
2个回答

14

确实是安全的。

如果没有您的保证,这将是未定义的:MyEnum(int(NUM_ENUMS) + 1),因为要保存的值(4)将大于枚举可以表示的范围([0, 3]);由于您确保m严格小于NUM_ENUMS,因此可以安全地使用MyEnum(m + 1)

另一方面,请注意,您可能会遇到自定义枚举类型的问题,例如:

enum OtherEnum {
    Foo = -1,
    Bar = 2,
    Baz = 8,
    NUM_OTHERENUM
};

所以这不是一种通用的做法。

我建议使用生成的数组进行迭代:

MyEnum const Values[] = { FOO, BAR, BLECH };

请注意,它可以轻松地从枚举的定义中生成,并且还避免了使用无意义的值(从业务角度来看)污染接口。


谢谢 - 我已经更新了问题,以澄清我的要求仅适用于连续的枚举值。 - Paul R

1

像Matthieu所说的那样,这样做是完全安全的,并且不会违反C++标准。

另外一件事情是,重载枚举的++运算符不仅是一种过度设计,而且已经被其他人指出存在问题(例如,如果枚举值不是线性的)。

因此,你需要的不是定义一个++运算符,而是一个迭代器。

我从这里 关于枚举 中借鉴了deft_code的解决方案,但稍作修改以适应你的例子。

template< typename T >
class Enum
{
public:
   class Iterator
   {
   public:
  Iterator( int value ) :
     m_value( value )
  { }

  T operator*( void ) const
  {
     return (T)m_value;
  }

  void operator++( void )
  {
     ++m_value;
  }

  bool operator!=( Iterator rhs )
  {
     return m_value != rhs.m_value;
  }

   private:
      int m_value;
   };

};

template< typename T >
typename Enum<T>::Iterator begin( Enum<T> )
{
   return typename Enum<T>::Iterator( (int)T::First );
}

template< typename T >
typename Enum<T>::Iterator end( Enum<T> )
{
   return typename Enum<T>::Iterator( ((int)T::Last) + 1 );
}

enum class MyEnum
{
   FOO,
   BAR,
   BLECH,
   NUM_ENUMS
};

int main()
{
   for( auto e: Enum<MyEnum>() )
   {
      std::cout << ((int)e) << std::endl;
   }
}

这可能仍对您来说过于繁琐,但更加简洁。另一段代码,但更为优雅的方法是here。在未来,C++11中引入的枚举类可能会在标准中具有迭代器。更新:由于您更新了值是连续的,并且它是C API所必需的(?),因此上述方法将不适用。

谢谢- C++11的东西很有趣,但我的枚举是作为C API的一部分定义的,需要从C++测试套件中调用,因此我需要使用一个纯粹的旧C枚举(虽然在C++上下文中)。 - Paul R
@woosah,提供的链接似乎已经失效。 - ZeroPhase

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接