宏不直接调用扩展,而是用间接扩展 [英] Macro not expanded with direct call, but expanded with indirect

查看:221
本文介绍了宏不直接调用扩展,而是用间接扩展的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下宏



  #include< boost / preprocessor.hpp> 

#define DB_FIELD(...)BOOST_PP_VARIADIC_TO_SEQ(__ VA_ARGS__)

#define DB_TOFIELD(type,name)\
private:\
类型名称## _; \
public:\
const type& get _ ## name(){返回名称## _;} \
void set _ ## name(const type& val){name ## _ = val; }

的#define GEN_ENUM_FIELD(R,数据,ELEM)BOOST_PP_CAT(FIELD_,BOOST_PP_SEQ_ELEM(1,ELEM)),

#定义DECLARE(类型,名称)DB_TOFIELD(类型,名)

的#define GEN_FIELD_DECL(R,数据,ELEM)宣布(BOOST_PP_SEQ_ELEM(0,ELEM),BOOST_PP_SEQ_ELEM(1,ELEM))

#定义DB_TABLE(名,...)类名: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__))\
枚举字段{\
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)

/ pre>

生成:

  class Test2:public DataBaseTable {
public:
constexpr static const char * get_table_name(){returnTest2; }
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; }
枚举字段{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(){returnTest2 }
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; }
枚举字段{FIELD_foo,FIELD_bar,FIELD_COUNT};
};

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


解决方案

你所运行到一个例外,如果他们论点的预处理器是如何扩展参数 ## 运算符。从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); (中间结果)
// => int y = 107; (最终扩展)


I've got the following macros

#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\
  };\
  };

Now the following code:

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

Generates:

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 };
};

Which is as ugly as I wrote it, but my concern is why do I need this level of indirection (DECLARE) in the GEN_FIELD_DECL macro ? The direct call to DB_TOFIELD

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

produces garbage:

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 };
};

The same behavior is reproduced with clang 3.7.1 and gcc 5.3

解决方案

What you are running into is an exception to how the preprocessor expands parameters if they are arguments to the # or ## operators. From C++.2011 §16.3.1¶1:

After the arguments for the invocation of a function-like macro have been identified, argument substitution takes place. A parameter in the replacement list, unless preceded by a # or ## preprocessing token or followed by a ## preprocessing token (see below), is replaced by the corresponding argument after all macros contained therein have been expanded. Before being substituted, each argument’s preprocessing tokens are completely macro replaced as if they formed the rest of the preprocessing file; no other preprocessing tokens are available.

The macro indirection avoids the exception clause, causing the argument to be expanded before being processed by the other macro.

For example:

#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)

这篇关于宏不直接调用扩展,而是用间接扩展的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆