如何根据预定义的宏(C ++预处理器)组合有效令牌?

时间:2014-04-22 12:01:39

标签: c++ macros c-preprocessor

假设某些令牌FOOBARDUD(可能更多)是#defined或不是EXTEND(name)。我想要一个生成有效扩展名的宏#define FOO #undef BAR #define DUD EXTEND(object) ,例如

object_foo_dud

扩展为

EXTEND

如果有n个宏标记(例如FOO,{{} BAR,可以编写小于O(2 n )行的宏DUD 1}}和#ifdef FOO # define ExtFOO(name) name ## _foo #else # define ExtFOO(name) name #endif #ifdef BAR # define ExtBAR(name) ExtFOO(name) ## _bar #else # define ExtBAR(name) ExtFOO(name) #endif #ifdef DUD # define ExtDUD(name) ExtBAR(name) ## _dud #else # define ExtDUD(name) ExtBAR(name) #endif #define EXTEND(name) ExtDUD(name) )?我认为应该可以使用O(n)行,但是如何?

试过这个

{{1}}

  

test.cc:26:5:错误:粘贴形成')_ dud',一个无效的预处理标记
          EXTEND(对象)
          ^

1 个答案:

答案 0 :(得分:3)

##运算符连接两个预处理标记,并且必须生成单个有效标记。例如,来自C99规范的第6.10.3.3节:

  

对于类似对象和类似函数的宏调用,在替换列表之前   重新检查更多宏名称以替换##预处理令牌的每个实例   在替换列表中(不是从参数中)被删除并进行前面的预处理   token与以下预处理标记连接在一起。专门处理地标预处理令牌:两个地方标记的连接导致单个地标标记预处理标记,并且地标标记与非地标标记预处理标记的连接导致非地标标记预处理标记。 如果结果不是有效的预处理令牌,则行为未定义。生成的令牌可用于进一步的宏替换。 ##运算符的评估顺序未指定。

因此扩展ExtBAR(name) ## _dud无效,因为它会产生ExtBAR(object)_dud

我会采用以下方法:

#ifdef FOO
#  define ValFOO _foo
#else
#  define ValFOO
#endif

#ifdef BAR
#  define ValBAR _bar
#else
#  define ValBAR
#endif

#ifdef DUD
#  define ValDUD _dud
#else
#  define ValDUD
#endif

#define CONCAT(a, b, c, d) a ## b ## c ## d
#define XCONCAT(a, b, c, d) CONCAT(a, b, c, d)
#define EXTEND(name) XCONCAT(name, ValFOO, ValBAR, ValDUD)

需要中间XCONCAT步骤,因为如果使用##连接宏参数,则不会展开它们。