【问题标题】:C programming, make change at two location with one macroC编程,用一个宏在两个位置进行更改
【发布时间】:2014-04-17 13:15:28
【问题描述】:
struct Error
{
   MACRO(1, Connect);
   MACRO(2, Timeout);
};    

我需要以这样的方式定义 MACRO() 上面的代码将生成以下代码。

struct Error
{  
   static const int Connect = 1;
   static const int Timeout = 2;
   const char * const name[] = {"Connect", "Timeout"};
};

这可能吗?或者有什么替代方法可以得到我想要做的事情?

【问题讨论】:

  • 你也许可以做到这一点,但它会很复杂,我不推荐它。你更大的目标是什么?你为什么要这个?好像是XY Problem
  • 我相信你想要做的事情不能用宏来实现。
  • 使用XMacro
  • @MohitJain 感谢您的链接。我已经用了很长一段时间了,但我从来不知道它有名字。

标签: c macros c-preprocessor


【解决方案1】:

您不能直接执行此操作,但如果您将宏移动到单独的位置(例如单独的文件),则可以:

ma​​cros.hpp

MACRO(1, Connect)
MACRO(2, Timeout)

#undef MACRO

另一个文件

struct Error
{
  #define MACRO(a, b) static const int b = a;
  #include "macros.hpp"

  const char * const name [] = {
  #define MACRO(a, b) #b,
  #include "macros.hpp"
  }
};

或者,您可以使用Boost.Preprocessor 实现类似的效果。

【讨论】:

  • 这通常是正确的解决方案。如果该数字用于查找名称,那么我将使用 Enum 自动生成正确的数组索引:#define MACRO(a, b) b##_Offset,enum { #include "macros.hpp" }; 这样,数组索引在编程上独立于使用了多少宏。 if (error==Connect) log_error(name[Connect_Offset]); 但也许你不需要那个?
【解决方案2】:

这是Boost.Preprocessor 解决方案:

#include <boost/preprocessor/seq/for_each.hpp>
#include <boost/preprocessor/seq/size.hpp>
#include <boost/preprocessor/tuple/elem.hpp>
#include <boost/preprocessor/stringize.hpp>

#define FIRST(a, b) a
#define SECOND(a, b) b

#define DECLARE_VAR(r, data, elem)              \
    static const int FIRST elem = SECOND elem;

#define NAME_ARRAY_ELEM(r, data, elem)          \
    BOOST_PP_STRINGIZE(FIRST elem), 

#define MACRO(seq)                                      \
    BOOST_PP_SEQ_FOR_EACH(DECLARE_VAR, ~, seq)          \
    const char * const name[] = {                       \
        BOOST_PP_SEQ_FOR_EACH(NAME_ARRAY_ELEM, ~, seq)  \
    }

int main()
{
    MACRO(((Connect, 1))((TimeOut, 2)));
    return 0;
}

您必须确保为每个 ((Token, value)) 对加上双括号,但是您的宏不需要单独的文件。

【讨论】:

    【解决方案3】:

    你想要的是有一个单独的列表,它会自动生成定义和名称列表,对吗?

    如果有,请在 google 中搜索 X Macros。

    例子:

    #define EXPAND_AS_DEFINITION(a, b) static const int b = a;
    #define EXPAND_AS_ARRAY(a, b) #b,
    
    #define STATE_TABLE(ENTRY)  \
       ENTRY(1, Connect)       \
    ENTRY(2, Timeout)   
    
    struct Error
    {       
       STATE_TABLE(EXPAND_AS_DEFINITION)
       static const char * const name[];      
    };
    
    const char * const Error::name[] = {STATE_TABLE(EXPAND_AS_ARRAY) 0};
    

    【讨论】:

      【解决方案4】:

      看起来您正在尝试定义一个enum Error,该enum Error 也将字符串作为成员。我会给你我自己的解决方案来解决这个问题。 (我没有解决这个问题,但我相信我的回答与我理解的 OP 正在尝试做的事情相关。)

      我刚刚意识到 OP 的目标是 C,而不是 C++,所以不确定这是否可以做到......

      MyEnum.hpp

      #define MYENUM(X,...)                                        \
          struct X {                                               \
              enum Enum {__VA_ARGS__};                             \
              static const std::vector<std::string> names;         \
              static X::Enum which(const std::string& s) {         \ 
                  return static_cast<X::Enum>(findEnum(s,names));  \
              }                                                    \
              static std::string str(X::Enum i) {                  \ 
                  return names[i];}                                \
          }
      

      这里findEnum() 只是对返回位置索引的向量进行线性搜索(此外,在我的实现中,如果找不到它,它会抛出所有可能正确输入的异常,我也会进行不区分大小写的比较)。请注意,有序映射而不是向量会更有效(O(log(n))而不是 O(n)),但我不太在意,因为在我的情况下这些东西的大小非常小。

      在上一个宏下面,将您的枚举声明为

      MYENUM(Error,Connect,Timeout); // I put the semicolon here not in the macro 
      

      然后在MyEnum.cpp 中添加

      #include <boost/assign/list_of.hpp>
      
      const std::vector<std::string> Error::names = boost::assign::list_of
      ("Connect")("Timeout");
      

      (我认为应该可以在现代编译器中使用初始化列表)。这里重要的是要保证顺序一致,否则就不行了。

      然后,你可以这样做:

      Error::Enum err1 = Error::Connect;
      Error::Enum err2 = Error::which("Timeout");
      std::cout << "Got " << Error::str(err1) << " error. Not good.\n";
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2023-04-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-04-20
        • 2020-11-05
        相关资源
        最近更新 更多