【问题标题】:Simplest method for iterating through contiguous enum values in C++ [duplicate]在 C++ 中迭代连续枚举值的最简单方法 [重复]
【发布时间】:2013-06-17 05:00:41
【问题描述】:

在 C++ 中迭代具有连续值的枚举的首选 simple 方法是什么?我发现以前关于这个主题的 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 ... 似乎对此很满意)?

【问题讨论】:

  • 也许一个附带的问题是你为什么要迭代一个枚举,如果你真的这样做,有没有更好的方法来表示命名值进行迭代?如何使用 std::map 容器
  • 这很好,因为您没有为元素定义自定义值,在它们之间留下空格(例如:FOO = 1,BAR = 5,BLECH = 7)
  • 你的第三次尝试应该没问题(见this answer
  • 我也一直想知道如何迭代枚举:Using enum in loops and value consistency
  • 有一个库Better Enums 提供您正在寻找的功能。它还允许将枚举解释为字符串,以及许多其他功能。开发人员声称它可能会进入 C++17 功能集。

标签: c++ for-loop enums


【解决方案1】:

确实很安全。

这将是未定义的: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 };

请注意,它很容易从枚举的定义中生成,并且还避免使用无意义的值(业务方面)污染接口。

【讨论】:

  • 谢谢 - 我已更新问题以澄清我的要求仅适用于连续的枚举值。
【解决方案2】:

就像 Matthieu 所说的那样,这样做是绝对安全的,并且不会以任何方式违反 C++ 标准。

作为旁注,在枚举上重载 ++ 运算符不仅是一种矫枉过正,而且其他人已经说明了一些问题(例如,如果枚举的值不是线性的)

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

我通过 deft_code 从这里 regarding enums 调整了以下解决方案,但稍微根据您的示例进行了调整。

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++ 上下文中)。
  • @woosah 提供的链接似乎已失效。
猜你喜欢
  • 2012-05-16
  • 2011-10-20
  • 1970-01-01
  • 2018-03-21
  • 2011-10-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-05-22
相关资源
最近更新 更多