是否可以定义一个预处理器宏,它将以下列方式扩展。
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/