c++ - 将参数添加到列表并在 C 预处理器宏中应用另一个宏

标签 c++ c c-preprocessor

是否可以定义一个预处理器宏,它将以下列方式扩展。

MACRO1(x) (y,z,w)
--> MACRO2(x,y,z,w)

MACRO1 的扩展能否以某种方式消耗宏调用后列表的左括号并将其替换为 MACRO2(x, 以便预处理器接受结果作为有效的宏调用(假设定义了 MACRO2)并且不会引发 unterminated argument list 错误?

我试过做这样的事情

#define STRANGE_MACRO(...) __VA_ARGS__
#define STRIP_PAREN(...) __VA_ARGS__)
#define PREPEND_AND_APPLY_STRANGE(x) STRANGE_MACRO(x,STRIP_PAREN

这样调用:

PREPEND_AND_APPLY_STRANGE(x) (y,z,w)

产生 unerminated argument list 错误。有没有办法让它发挥作用?

至于我想要这种行为的原因,是为了美学,我认为这样的宏调用看起来更好

MACRO1(identifier) (
    more
    complex
    arguments
)

MACRO2(identifier,
    more
    complex
    arguments
)

我只是希望前者转化为后者。如果这在预处理器规则内是不可能的,那没什么大不了的,我会接受它,但如果是的话,我想知道诀窍。

最佳答案

如果你想在替换列表中加入一个不匹配的左括号,你需要添加一个间接层:

#define LPAREN (

#define PREPEND_AND_APPLY_STRANGE(x) STRANGE_MACRO LPAREN x,STRIP_PAREN

这样,在正确的语法完成之前,括号不会被视为调用的一部分。

不幸的是,这种技术有一个局限性:当对 STRANGE_MACRO 的调用完全构建时,它已经过了可以重新扫描的点 - 因为表达式的开始和结束是发生在同一级别的两个不同调用,整个过程从未出现在一个重新扫描列表中——而且永远不会真正展开;您只会将 STRANGE_MACRO ( x,y,z,w) 转储到您的输出中。您需要在顶层强制重新扫描:

#define EXPAND(...) __VA_ARGS__

宏什么都不做,但确实意味着它的参数作为一个完整的单元被放入重新扫描列表中,因此最终会展开。所以最接近你想要的语法是这样的:

EXPAND(

MACRO1(identifier) (
    ....
)
MACRO1(identifier) (
    ....
)

)

...所以您不需要用自己的 EXPAND 毁坏每个自定义 block ,但您确实需要将整个程序封装在一个程序中。不,你不能通过在 EXPAND 中放置一个 #include 指令来隐藏包装器,因为指令不能出现在调用中。 (不过,也许您可​​以通过重新发明 namespace 或您的语法可能需要的类似东西来利用它。)

这也有一个缺点,即 C 编译器会将您的整个程序 视为在一行中,这会在一定程度上损害错误报告 - 尽管您已经解决了这个问题的一半,因为每个声明 block 如果原始版本有效,似乎也只在一行上。

关于c++ - 将参数添加到列表并在 C 预处理器宏中应用另一个宏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23385337/

相关文章:

c - 选择小于架构大小的变量是一个有效的选择吗?

printing - 是否有一种可移植的方法来打印来自 C 预处理器的消息?

c++ - 链接器、库和目录信息

c - 二维字符数组返回 SEGFAULT

C - 在实际问题点之前提出的段错误

c++ - 当存在: auto lambda = [](){};行时,Cppcheck不输出警告

C++ 通过常量引用传递结构

c - C include guards到底做了什么?

c++ - 使用 bool 非类型参数实例化类模板时出错

c++ - 本地版 Google Maps API