【问题标题】:Iterate through #defines遍历#defines
【发布时间】:2014-12-17 12:34:31
【问题描述】:

我的应用程序中有一个配置文件,如下所示。此配置需要在构建程序之前完成。

#define NO_OF_COLORS 8   

#define COLOR_RESPONCE_1 'R'
#define COLOR_RESPONCE_2 'G'
#define COLOR_RESPONCE_3 'B'
#define COLOR_RESPONCE_4 'M'
#define COLOR_RESPONCE_5 'C'
#define COLOR_RESPONCE_6 'Y'
#define COLOR_RESPONCE_7 'O'
#define COLOR_RESPONCE_8 'P'

在一个类中,我需要将这些值添加到 std::vector。有没有办法遍历这些定义。可能正在使用宏?

【问题讨论】:

  • 我不认为你可以遍历定义,因为它是永久性的,不能被篡改
  • 请有人告诉我为什么某些程序员喜欢宏
  • 还可以在 RGB 和 CMYK 之间进行转换
  • @Ed Heal, chars 是控制台应用程序的预期用户输入。填充向量用于验证输入
  • 英文会很好

标签: c++ c-preprocessor


【解决方案1】:

您可以使用Boost.Preprocessor 库。它提供了为预处理器模拟控制结构和数据结构的宏。例如。你可以像这样迭代你的颜色:

#include <iostream>
#include <boost/preprocessor.hpp>

#define NO_OF_COLORS 8

#define COLOR_RESPONCE_1 'R'
#define COLOR_RESPONCE_2 'G'
#define COLOR_RESPONCE_3 'B'
#define COLOR_RESPONCE_4 'M'
#define COLOR_RESPONCE_5 'C'
#define COLOR_RESPONCE_6 'Y'
#define COLOR_RESPONCE_7 'O'
#define COLOR_RESPONCE_8 'P'

#define PRINT_COLOR(z, x, _)                    \
  std::cout << BOOST_PP_CAT(COLOR_RESPONCE_, x) << std::endl;

int main()
{
  BOOST_PP_REPEAT_FROM_TO(1, NO_OF_COLORS, PRINT_COLOR, 0);
}

BOOST_PP_REPEAT_FROM_TO 用计数器模拟循环,PRINT_COLOR 宏实现循环体。

就我个人而言,只有在别无选择的情况下,我才会使用 Boost.Preprocessor。它只模拟控制结构并有许多限制(例如,在多次循环迭代中),调试预处理器代码并不比繁重的模板代码简单。

关于风格的说明。 虽然预处理器继承自 C 并且对于单独(以及条件)编译是必需的,但它与现代 C++ 格格不入,甚至对于 98 之前的 C++ 来说也是格格不入的.如果您需要常量,您可以并且应该使用 constenum(甚至更好地使用 enum class)或 constexpr 来定义它们强>。这些常量可以放在命名空间中以避免名称冲突,它们可以保证只初始化一次(extern const)。

【讨论】:

    【解决方案2】:

    为什么不将这些存储在std::string 而不是std::vector

    const std::string COLDATA = "RGBMCYOP";
    

    您仍然可以使用索引[]std::vector 一样访问它:

    COLDATA[3]; // == 'M'
    

    或者如果你仍然想把它放在一个向量中,你可以这样做:

    const std::vector<char> COLDATAVEC(COLDATA.begin(), COLDATA.end());
    

    如果您使用的是 C++11,则可以将其放入 std::vector 而不使用 std::string

    const std::vector<char> COLDATAVEC = {'R', 'G', 'B', 'M', 'C', 'Y', 'O', 'P'};
    

    【讨论】:

      【解决方案3】:

      您无法通过宏进行迭代。预处理器编译可能是多阶段的,但名称本身将仅在(预处理的)第一遍中解析。

      如果你这样做会更好:

      const char Colors[] = {'R','G','B','C','M','Y','O','P'};
      

      然后使用sizeof(Colors) / sizeof(Colors[0]) 查找此数组中的元素数。使用循环进行迭代:

      for(size_t index = 0; index < sizeof(Colors) / sizeof(Colors[0]); ++index)
      {}
      

      或者,如果您使用的是支持基于范围的 for 循环的 C++11 编译器,您可以使用:

      for(char color : Colors) 
      { 
         // Use 'color'
      }
      

      更简单:

      for(auto color : Colors) 
      { 
         // Use 'color'
      }
      

      【讨论】:

        【解决方案4】:

        定义您自己的迭代机制(限于 10 次迭代):

        #define ITER_0(MACRO, ACTION, DATA)
        #define ITER_1(MACRO, ACTION, DATA) ITER_0(MACRO, ACTION, DATA) ACTION(MACRO##1, DATA)
        #define ITER_2(MACRO, ACTION, DATA) ITER_1(MACRO, ACTION, DATA) ACTION(MACRO##2, DATA)
        #define ITER_3(MACRO, ACTION, DATA) ITER_2(MACRO, ACTION, DATA) ACTION(MACRO##3, DATA)
        #define ITER_4(MACRO, ACTION, DATA) ITER_3(MACRO, ACTION, DATA) ACTION(MACRO##4, DATA)
        #define ITER_5(MACRO, ACTION, DATA) ITER_4(MACRO, ACTION, DATA) ACTION(MACRO##5, DATA)
        #define ITER_6(MACRO, ACTION, DATA) ITER_5(MACRO, ACTION, DATA) ACTION(MACRO##6, DATA)
        #define ITER_7(MACRO, ACTION, DATA) ITER_6(MACRO, ACTION, DATA) ACTION(MACRO##7, DATA)
        #define ITER_8(MACRO, ACTION, DATA) ITER_7(MACRO, ACTION, DATA) ACTION(MACRO##8, DATA)
        #define ITER_9(MACRO, ACTION, DATA) ITER_8(MACRO, ACTION, DATA) ACTION(MACRO##9, DATA)
        #define ITER_10(MACRO, ACTION, DATA) ITER_9(MACRO, ACTION, DATA) ACTION(MACRO##10, DATA)
        
        #define ITER_I(ITERS, MACRO, ACTION, DATA) ITER_##ITERS(MACRO, ACTION, DATA)
        #define ITER(ITERS, MACRO, ACTION, DATA) ITER_I(ITERS, MACRO, ACTION, DATA)
        

        定义将在每次迭代中调用的操作:

        #define PRINT(MACRO, DATA) std::cout << MACRO; 
        #define ADD_TO_VECTOR(MACRO, DATA) DATA.push_back(MACRO);
        

        使用如下操作:

        std::vector<char> v;
        ITER(NO_OF_COLORS, COLOR_RESPONCE_, ADD_TO_VECTOR, v)
        
        ITER(NO_OF_COLORS, COLOR_RESPONCE_, PRINT, ~)
        

        DEMO

        【讨论】:

          【解决方案5】:

          您似乎想遍历枚举。 C++ 不支持这一点(其他语言,例如 Java,默认情况下确实有这种行为。要解决这个问题,您需要创建一个可迭代、长度恒定且定义明确的数据结构,因此易于维护。

          例如,您可以将数据存储在std::array(或c++11之前的std::tr1::array)中

          const std::array<BYTE,8> Colors = { { 'R','G','B','C','M','Y','O','P' } };
          

          std::array 具有迭代器和 size() 运算符。所以你可以做

          for( std::array<BYTE,8>::const_iterator itr = Colors.begin();
               itr != Colors.end();
               ++itr )
          {
              // use (*itr)
          }
          

          或者如果你想要索引

          for( std::size_t index = 0 ; index < Colors.size() ; ++index )
          {
              // use Colors[i]
          }
          

          您可以在c++11 中使用:

          for( auto color : Colors )
          {
               // use color     
          } 
          

          您也可以通过以下方式将它们复制到std::vector

          std::vector<BYTE> Colors_vector( Colors.begin(), Colors.end() );
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2010-10-21
            • 2018-10-05
            • 2018-07-15
            • 2014-01-23
            • 2018-11-03
            相关资源
            最近更新 更多