【问题标题】:Macro not expanded with direct call, but expanded with indirect宏不通过直接调用扩展,而是通过间接调用扩展
【发布时间】:2016-02-29 21:59:42
【问题描述】:

我有以下宏

#include <boost/preprocessor.hpp>

#define DB_FIELD(...) BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__)

#define DB_TOFIELD(type,name) \
  private:\
  type name##_;\
  public:\
  const type& get_##name(){return name##_;}\
  void set_##name(const type& val) { name##_ = val; }

#define GEN_ENUM_FIELD(r,data,elem) BOOST_PP_CAT(FIELD_,BOOST_PP_SEQ_ELEM(1,elem)),

#define DECLARE(type, name) DB_TOFIELD(type, name)

#define GEN_FIELD_DECL(r, data, elem) DECLARE(BOOST_PP_SEQ_ELEM(0,elem),BOOST_PP_SEQ_ELEM(1,elem))

#define DB_TABLE(name, ...) class name : public DataBaseTable {\
  public:\
  constexpr static const char *get_table_name() { return #name; }\
  BOOST_PP_LIST_FOR_EACH(GEN_FIELD_DECL,, BOOST_PP_VARIADIC_TO_LIST(__VA_ARGS__)) \
  enum Fields{ \
  BOOST_PP_LIST_FOR_EACH(GEN_ENUM_FIELD,, BOOST_PP_VARIADIC_TO_LIST(__VA_ARGS__))\
  FIELD_COUNT\
  };\
  };

下面的代码:

DB_TABLE(Test2,
  DB_FIELD(int, foo),
  DB_FIELD(int, bar)
)

生成:

class Test2 : public DataBaseTable {
public:
  constexpr static const char *get_table_name() { return "Test2"; }
private:
  int foo_;
public:
  const int &get_foo() { return foo_; }
  void set_foo(const int &val) { foo_ = val; }
private:
  int bar_;
public:
  const int &get_bar() { return bar_; }
  void set_bar(const int &val) { bar_ = val; }
  enum Fields { FIELD_foo, FIELD_bar, FIELD_COUNT };
};

这和我写的一样难看,但我担心的是为什么在 GEN_FIELD_DECL 宏中需要这种级别的间接 (DECLARE)?直接调用 DB_TOFIELD

#define GEN_FIELD_DECL(r, data, elem) DB_TOFIELD(BOOST_PP_SEQ_ELEM(0,elem),BOOST_PP_SEQ_ELEM(1,elem))

产生垃圾:

class Test2 : public DataBaseTable {
public:
  constexpr static const char *get_table_name() { return "Test2"; }
private:
  int foo _;
public:
  const int &get_BOOST_PP_SEQ_ELEM(1, (int)(foo))() { return foo _; }
  void set_BOOST_PP_SEQ_ELEM(1, (int)(foo))(const int &val) { foo _ = val; }
private:
  int bar _;
public:
  const int &get_BOOST_PP_SEQ_ELEM(1, (int)(bar))() { return bar _; }
  void set_BOOST_PP_SEQ_ELEM(1, (int)(bar))(const int &val) { bar _ = val; }
  enum Fields { FIELD_foo, FIELD_bar, FIELD_COUNT };
};

clang 3.7.1 和 gcc 5.3 重现了相同的行为

【问题讨论】:

    标签: c++ macros variadic-macros boost-preprocessor


    【解决方案1】:

    如果它们是### 运算符的参数,您遇到的是预处理器如何扩展参数的异常。来自 C++.2011 §16.3.1¶1:

    在确定了调用类函数宏的参数后,参数替换 发生。替换列表中的参数,除非前面有 ### 预处理标记或 后跟一个## 预处理标记(见下文),在所有宏之后被相应的参数替换 其中包含的内容已扩展。在被替换之前,每个参数的预处理标记是 完全替换宏,就好像它们形成了预处理文件的其余部分;没有其他预处理令牌 可用。

    宏间接避免了异常子句,导致参数在被另一个宏处理之前被扩展。

    例如:

    #define FOO 10
    #define BAR(x) x ## 7
    #define BAR2(x) BAR(x)
    
    int x = BAR(FOO);      // => int x = FOO7;
    
    int y = BAR2(FOO);     // => int y = BAR(10); (intermediate result)
                           // => int y = 107;     (final expansion)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-11-04
      • 1970-01-01
      • 1970-01-01
      • 2015-10-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-02-09
      相关资源
      最近更新 更多