Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/142.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在C++; 在C++中,枚举枚举(运行时或编译时(首选))和每次迭代调用函数/生成代码是可能的吗?_C++_Enums_Metaprogramming_Enumeration - Fatal编程技术网

在C++; 在C++中,枚举枚举(运行时或编译时(首选))和每次迭代调用函数/生成代码是可能的吗?

在C++; 在C++中,枚举枚举(运行时或编译时(首选))和每次迭代调用函数/生成代码是可能的吗?,c++,enums,metaprogramming,enumeration,C++,Enums,Metaprogramming,Enumeration,示例用例: enum abc { start a, b, c, end } for each (__enum__member__ in abc) { function_call(__enum__member__); } 合理的重复: 没有一点体力劳动,两者都不可能实现。如果您愿意深入研究该领域,宏可以完成很多工作。否 但是,您可以定义自己的类,该类通过迭代实现类似枚举的功能。您可能还记得1.5Java之前的

示例用例:

enum abc
{    
    start
    a,
    b,
    c,
    end
}    
for each (__enum__member__ in abc)
{    
    function_call(__enum__member__);    
}

合理的重复:


    • 没有一点体力劳动,两者都不可能实现。如果您愿意深入研究该领域,宏可以完成很多工作。


      但是,您可以定义自己的类,该类通过迭代实现类似枚举的功能。您可能还记得1.5Java之前的一个技巧,称为“类型安全枚举设计模式”。你可以做C++等价的。

      扩展Konrad所说的,在“每次迭代生成代码”的情况下,一个可能的习惯用法是使用包含的文件来表示枚举:

      mystuff.h:

      #ifndef LAST_ENUM_ELEMENT
      #define LAST_ENUM_ELEMENT(ARG) ENUM_ELEMENT(ARG)
      #endif
      
      ENUM_ELEMENT(foo)
      ENUM_ELEMENT(bar)
      LAST_ENUM_ELEMENT(baz)
      
      // not essential, but most likely every "caller" should do it anyway...
      #undef LAST_ENUM_ELEMENT
      #undef ENUM_ELEMENT
      
      枚举h:

      // include guard goes here (but mystuff.h doesn't have one)
      
      enum element {
          #define ENUM_ELEMENT(ARG) ARG,
          #define LAST_ENUM_ELEMENT(ARG) ARG
          #include "mystuff.h"
      }
      
      main.cpp:

      #include "enum.h"
      #define ENUM_ELEMENT(ARG) void do_##ARG();
      #include "mystuff.h"
      
      element value = getValue();
      switch(value) {
          #define ENUM_ELEMENT(ARG) case ARG: do_##ARG(); break;
          #include "mystuff.h"
          default: std::terminate();
      }
      
      因此,要添加新元素“qux”,您需要将其添加到mystuff.h并编写
      do_qux
      函数。你不必触摸调度代码


      当然,如果枚举中的值需要是特定的非连续整数,那么最终需要维护枚举定义和
      enum\u元素(foo)
      。。。单独列出,这很混乱。

      这对我来说似乎有点骇人听闻,但可能适合您的目的:

      enum Blah {
        FOO,
        BAR,
        NUM_BLAHS
      };
      
      // later on
      for (int i = 0; i < NUM_BLAHS; ++i) {
        switch (i) {
        case FOO:
          // foo stuff
          break;
        case BAR:
          // bar stuff
          break;
        default:
          // you're missing a case statement
        }
      }
      
      enum废话{
      福,
      酒吧,
      数字布拉斯
      };
      //后来
      for(int i=0;i
      如果需要特殊的起始值,可以将其设置为常量并在枚举中设置。我没有检查它是否编译,但它应该很接近那里:-)。希望这有帮助


      我认为这种方法对于您的用例来说可能是一种很好的平衡。如果您不需要对一堆不同的枚举类型执行此操作,并且不想处理预处理器的内容,请使用它。只需确保您发表评论,并可能添加一个TODO,以便在以后将其更改为更好的:-)。

      C++目前不提供枚举器迭代。尽管如此,有时还是需要这样做。常见的解决方法是添加标记开始和结束的值。例如:

      enum Color
      {
          Color_Begin,
          Color_Red = Color_Begin,
          Color_Orange,
          Color_Yellow,
          Color_Green,
          Color_Blue,
          Color_Indigo,
          Color_Violet,
          Color_End
      };
      
      void foo(Color c)
      {
      }
      
      
      void iterateColors()
      {
          for (size_t colorIdx = Color_Begin; colorIdx != Color_End; ++colorIdx)
          {
              foo(static_cast<Color>(colorIdx));
          }
      }
      
      枚举颜色
      {
      颜色开始,
      Color\u Red=Color\u Begin,
      橙色,
      黄色,
      绿色,
      蓝色,
      靛蓝色,
      紫罗兰色,
      颜色结束
      };
      void foo(颜色c)
      {
      }
      void iterateColors()
      {
      对于(大小\u t colorIdx=Color\u开始;colorIdx!=Color\u结束;++colorIdx)
      {
      foo(静态_-cast(colorIdx));
      }
      }
      
      要添加到@StackedCrooked答案,您可以重载
      运算符+++
      运算符--
      运算符*
      ,并具有类似迭代器的功能

      enum Color {
          Color_Begin,
          Color_Red = Color_Begin,
          Color_Orange,
          Color_Yellow,
          Color_Green,
          Color_Blue,
          Color_Indigo,
          Color_Violet,
          Color_End
      };
      
      namespace std {
      template<>
      struct iterator_traits<Color>  {
        typedef Color  value_type;
        typedef int    difference_type;
        typedef Color *pointer;
        typedef Color &reference;
        typedef std::bidirectional_iterator_tag
          iterator_category;
      };
      }
      
      Color &operator++(Color &c) {
        assert(c != Color_End);
        c = static_cast<Color>(c + 1);
        return c;
      }
      
      Color operator++(Color &c, int) {
        assert(c != Color_End); 
        ++c;
        return static_cast<Color>(c - 1);
      }
      
      Color &operator--(Color &c) {
        assert(c != Color_Begin);
        return c = static_cast<Color>(c - 1);
      }
      
      Color operator--(Color &c, int) {
        assert(c != Color_Begin); 
        --c;
        return static_cast<Color>(c + 1);
      }
      
      Color operator*(Color c) {
        assert(c != Color_End);
        return c;
      }
      
      执行情况如下

      template<typename T>
      struct enum_identity { 
        typedef T type; 
      };
      
      namespace details {
      void begin();
      void end();
      }
      
      template<typename Enum>
      struct enum_iterator 
        : std::iterator<std::bidirectional_iterator_tag, 
                        Enum> {
        enum_iterator():c(end()) { }
      
        enum_iterator(Enum c):c(c) { 
          assert(c >= begin() && c <= end());
        }
      
        enum_iterator &operator=(Enum c) {
          assert(c >= begin() && c <= end());
          this->c = c; 
          return *this;
        }
      
        static Enum begin() {
          using details::begin; // re-enable ADL
          return begin(enum_identity<Enum>());
        }
      
        static Enum end() {
          using details::end; // re-enable ADL
          return end(enum_identity<Enum>());
        }
      
        enum_iterator &operator++() {
          assert(c != end() && "incrementing past end?");
          c = static_cast<Enum>(c + 1);
          return *this;
        }
      
        enum_iterator operator++(int) {
          assert(c != end() && "incrementing past end?");
          enum_iterator cpy(*this);
          ++*this;
          return cpy;
        }
      
        enum_iterator &operator--() {
          assert(c != begin() && "decrementing beyond begin?");
          c = static_cast<Enum>(c - 1);
          return *this;
        }
      
        enum_iterator operator--(int) {
          assert(c != begin() && "decrementing beyond begin?");
          enum_iterator cpy(*this);
          --*this;
          return cpy;
        }
      
        Enum operator*() {
          assert(c != end() && "cannot dereference end iterator");
          return c;
        }
      
        Enum get_enum() const {
          return c;
        }
      
      private:
        Enum c;
      };
      
      template<typename Enum>
      bool operator==(enum_iterator<Enum> e1, enum_iterator<Enum> e2) {
        return e1.get_enum() == e2.get_enum();
      }
      
      template<typename Enum>
      bool operator!=(enum_iterator<Enum> e1, enum_iterator<Enum> e2) {
        return !(e1 == e2);
      }
      
      模板
      结构枚举单位{
      T型;
      };
      命名空间详细信息{
      void begin();
      空端();
      }
      模板
      结构枚举迭代器
      :std::迭代器{
      枚举迭代器():c(end()){
      枚举迭代器(枚举c):c(c){
      断言(c>=begin()&&c=begin()&&c=c;
      归还*这个;
      }
      静态枚举开始(){
      使用详细信息::begin;//重新启用ADL
      返回开始(enum_identity());
      }
      静态枚举结束(){
      使用详细信息::end;//重新启用ADL
      返回端(enum_identity());
      }
      枚举迭代器和运算符++(){
      断言(c!=end()&&“递增超过end?”);
      c=静态(c+1);
      归还*这个;
      }
      枚举迭代器运算符++(int){
      断言(c!=end()&&“递增超过end?”);
      枚举迭代器cpy(*this);
      ++*这,;
      返回cpy;
      }
      枚举迭代器和运算符--(){
      断言(c!=begin()&&“在begin之后递减?”);
      c=静态(c-1);
      归还*这个;
      }
      枚举迭代器运算符--(int){
      断言(c!=begin()&&“在begin之后递减?”);
      枚举迭代器cpy(*this);
      --*这,;
      返回cpy;
      }
      枚举运算符*(){
      断言(c!=end()&&“无法取消引用end迭代器”);
      返回c;
      }
      枚举获取_Enum()常量{
      返回c;
      }
      私人:
      枚举c;
      };
      模板
      布尔运算符==(枚举迭代器e1,枚举迭代器e2){
      返回e1.get_enum()==e2.get_enum();
      }
      模板
      布尔运算符!=(枚举迭代器e1,枚举迭代器e2){
      返回!(e1==e2);
      }
      
      您可以使用TMP静态执行一些建议的运行时技术

      #include <iostream>
      
      enum abc
      {
          a,
          b,
          c,
          end
      };
      
      void function_call(abc val)
      {
          std::cout << val << std::endl;
      }
      
      template<abc val>
      struct iterator_t
      {
          static void run()
          {
              function_call(val);
      
              iterator_t<static_cast<abc>(val + 1)>::run();
          }
      };
      
      template<>
      struct iterator_t<end>
      {
          static void run()
          {
          }
      };
      
      int main()
      {
          iterator_t<a>::run();
      
          return 0;
      }
      
      请参阅Abrahams的第1章,Gurtovoy“C++模板元编程”,了解对该技术的良好处理。与建议的运行时技术相比,采用这种方法的优势在于,当您优化此代码时,它可以内联静态,大致相当于:

      function_call(a);
      function_call(b);
      function_call(c);
      
      内联函数\u需要编译器提供更多帮助


      对其他枚举迭代技术的相同批评也适用于此。只有当枚举从一个到一个连续递增时,此技术才有效。

      我通常这样做:

      enum abc
      {    
          abc_begin,
          a = abc_begin,
          b,
          c,
          abc_end
      };
      
      void foo()
      {
          for( auto&& r : range(abc_begin,abc_end) )
          {
              cout << r;
          }
      }
      

      我喜欢模板制作,但我会记下这一点,供我将来/其他人使用,这样我们就不会对上面的任何一项感到迷茫

      枚举便于以已知的顺序方式进行比较。为了便于对整数值进行可读性,它们通常被硬编码到函数中。有点类似于预处理器定义,只是它们不被文字替换,而是在运行时保存和访问

      如果我们有一个定义html错误代码的枚举,并且我们知道500中的错误代码是服务器错误,那么最好阅读以下内容:

      enum HtmlCodes {CONTINUE_CODE=100,CLIENT_ERROR=400,SERVER_ERROR=500,NON_STANDARD=600};
      
      if(errorCode >= SERVER_ERROR && errorCode < NON_STANDARD)
      
      enum HtmlCodes{CONTINUE_code=100,CLIENT_ERROR=400,SERVER_ERROR=500,NON_STANDARD=600};
      如果(错误代码>=服务器错误和错误代码<非标准)
      

      if(errorCode>=500&&errorCode<600)
      
      关键是,它们类似于数组!,但用于转换整数值

      简短示例:

      enum Suit {Diamonds, Hearts, Clubs, Spades};
      //does something with values in the enum past "Hearts" in this case
      for(int i=0;i<4;i++){
         //Could also use i or Hearts, because the enum will turns these both back into an int 
         if( (Suit)(i) > 1 )
         {
            //Whatever we'd like to do with (Suit)(i)
         }
      }
      
      enum套装{钻石、红心、梅花、黑桃};
      //使用菜单中的值执行某些操作
      
      enum abc
      {    
          abc_begin,
          a = abc_begin,
          b,
          c,
          abc_end
      };
      
      void foo()
      {
          for( auto&& r : range(abc_begin,abc_end) )
          {
              cout << r;
          }
      }
      
      template <typename T>
      class Range
      {
      public:
          Range( const T& beg, const T& end ) : b(beg), e(end) {}
          struct iterator
          {
              T val;
              T operator*() { return val; }
              iterator& operator++() { val = (T)( 1+val ); return *this; }
              bool operator!=(const iterator& i2) { return val != i2.val; }
          };
          iterator begin() const { return{b}; }
          iterator end() const { return{e}; }
      private:
          const T& b;
          const T& e;
      };
      
      template <typename T>
      Range<T> range( const T& beg, const T& end ) { return Range<T>(beg,end); }
      
      enum HtmlCodes {CONTINUE_CODE=100,CLIENT_ERROR=400,SERVER_ERROR=500,NON_STANDARD=600};
      
      if(errorCode >= SERVER_ERROR && errorCode < NON_STANDARD)
      
      if(errorCode >= 500 && errorCode < 600)
      
      enum Suit {Diamonds, Hearts, Clubs, Spades};
      //does something with values in the enum past "Hearts" in this case
      for(int i=0;i<4;i++){
         //Could also use i or Hearts, because the enum will turns these both back into an int 
         if( (Suit)(i) > 1 )
         {
            //Whatever we'd like to do with (Suit)(i)
         }
      }
      
      char* Suits[4] = {"Diamonds", "Hearts", "Clubs", "Spades"};
      //Getting a little redundant
      cout << Suits[Clubs] << endl;
      //We might want to add this to the above
      //cout << Suits[(Suit)(i)] << endl;