【问题标题】:How to compose valid token depending on pre-defined macros (C++ preprocessor)?如何根据预定义的宏(C++ 预处理器)组成有效的令牌?
【发布时间】:2014-04-22 12:01:38
【问题描述】:

假设某些标记FOOBARDUD(可能还有更多)是否为#defined。我想要一个宏EXTEND(name) 生成一个有效的扩展名,例如

#define FOO
#undef  BAR
#define DUD
EXTEND(object)

扩展到

object_foo_dud

如果有n 宏标记(如FOOBARDUD )?我认为 O(n) 行应该是可能的,但是如何?

我已经尝试过

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

但是

test.cc:26:5: 错误:粘贴形成的 ')_dud',一个无效的预处理令牌
扩展(对象)
^

【问题讨论】:

    标签: c++ macros c-preprocessor


    【解决方案1】:

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

    对于类对象和类函数宏调用,在替换列表之前 重新检查要替换的更多宏名称,## 预处理标记的每个实例 在替换列表中(不是来自参数)被删除并且前面的预处理 令牌与以下预处理令牌连接。 Placemarker 预处理令牌经过特殊处理:两个 placemarker 的串联产生单个 placemarker 预处理令牌,placemarker 与非placemarker 预处理令牌的串联产生非placemarker 预处理令牌。 如果结果不是有效的预处理标记,则行为未定义。生成的标记可用于进一步的宏替换。 ## 运算符的求值顺序未指定。

    所以扩展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 步骤,因为如果使用## 连接宏参数,则不会扩展它们。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-01-26
      • 1970-01-01
      • 2021-12-29
      • 1970-01-01
      • 1970-01-01
      • 2010-10-17
      • 1970-01-01
      相关资源
      最近更新 更多