如何将宏展开的结果分离为不同的参数?
我正在编写一些 Boost.Preprocessor 元程序,但遇到以下问题。考虑以下宏(这是为了说明问题而进行的简化):
#define ITERATION_IMPL(p1, p2, p3, p4) ((p1),(p2),(p3),(p4))
#define ITERATION(args) ITERATION_IMPL(hello, args(), world)
#define ARGS() a, b
ITERATION(ARGS)
预处理的输出是这样的:
((hello),(a, b),(world),())
这表明 args()
没有分成多个参数。根据我对标准的理解,宏的参数在粘贴到替换列表之前已完全扩展。因此,我期望以下扩展序列:
ITERATION(ARGS)
ITERATION_IMPL(hello, ARGS(), world)
ITERATION_IMPL(hello, a, b, world)
((hello),(a),(b),(world))
这是我想要的结果。如何在不修改 ITERATION_IMPL 和调用本身的情况下实现它?
编辑:如果不可能(我猜是),请根据 C 或 C++ 的任何标准进行解释。
I'm writing some Boost.Preprocessor metaprogram, and I have the following problem. Consider the following macros (this is a simplification to illustrate the problem):
#define ITERATION_IMPL(p1, p2, p3, p4) ((p1),(p2),(p3),(p4))
#define ITERATION(args) ITERATION_IMPL(hello, args(), world)
#define ARGS() a, b
ITERATION(ARGS)
The preprocessed output is this:
((hello),(a, b),(world),())
This shows that args()
is not separated into multiple arguments. According to my understanding of the standard, the arguments of the macro are fully expanded before being pasted into the replacement-list. Therefore, I would expect the following expansion sequence:
ITERATION(ARGS)
ITERATION_IMPL(hello, ARGS(), world)
ITERATION_IMPL(hello, a, b, world)
((hello),(a),(b),(world))
That is my desired result. How can I achieve it without modifying ITERATION_IMPL
and the invocation itself?
Edit: If it's impossible (and I guess it is), please explain it based on any standard of C or C++.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我认为如果遇到
ITERATION(ARGS)
,则需要ITERATION_IMPL(hello, args(), world)
,将args
替换为ARGS
,然后重新扫描。ITERATION_IMPL(hello, ARGS(), world)
是对ITERATION_IMPL
的调用。因此,它需要((p1),(p2),(p3),(p4))
,并将p2
替换为ARGS()
(以及其他参数)。然后它会重新扫描并解析为((hello),(a, b),(world),())
。我不知道为什么它会在你的情况下调用带有 3 个参数的 4 参数宏。您可以这样做
,这将采用
X
,替换(hello, ARGS(), world)
,然后重新扫描,导致ARGS()
为替换为a, b
。生成的标记字符串ITERATION_IMPL (hello, a, b, world)
将执行您期望的操作。编辑:用 GCC 测试:)
编辑:我注意到你想要字符串
((hello),(a),(b),(world))
,但我的答案产生字符串ITERATION_IMPL (你好,a,b,世界)
。我认为这是因为当它在调用ITERATION
后重新扫描时,它会将IERATION_IMPL EVAL((hello, ARGS(), world))
替换为ITERATION_IMPL (hello, a, b,wold)
。然后,它需要再次扫描才能注意到它现在可以使用这些参数调用 ITERATION_IMPL。所以ITERATION
应该是当外部
EVAL
的X
被ITERATION_IMPL EVAL((hello, args(), world)) 替换时
,它会重新扫描并生成ITERATION_IMPL (hello, a, b, world)
以调用EVAL
。然后它再次重新扫描 ITERATION 的调用并生成您真正想要的序列。I think if
ITERATION(ARGS)
is encountered, it takesITERATION_IMPL(hello, args(), world)
, replacesargs
withARGS
, and then rescans.ITERATION_IMPL(hello, ARGS(), world)
is an invocation ofITERATION_IMPL
. Therefor, it takes((p1),(p2),(p3),(p4))
, and replacesp2
byARGS()
(along with the other parameters). It then rescans and resolves to((hello),(a, b),(world),())
. I don't know why it works that it calls a 4-parameter macro with 3 arguments in your case.You could do
That would take
X
, substitute(hello, ARGS(), world)
, and then rescan, causingARGS()
to be replaced bya, b
. The resulting token stringITERATION_IMPL (hello, a, b, world)
would then do what you expected.EDIT: Tested with GCC :)
EDIT: I noticed you want the string
((hello),(a),(b),(world))
, but my answer yields the stringITERATION_IMPL (hello, a, b, world)
. I think that's because when it rescans after callingITERATION
, it replacesIERATION_IMPL EVAL((hello, ARGS(), world))
byITERATION_IMPL (hello, a, b, wold)
. Then it would need another scan to notice that it can now invokeITERATION_IMPL
with those arguments. SoITERATION
should beWhen
X
for the outerEVAL
is substituted byITERATION_IMPL EVAL((hello, args(), world))
, it rescans and yieldsITERATION_IMPL (hello, a, b, world)
for the invocation ofEVAL
. Then it rescans again for the invocation ofITERATION
and yields the sequence you really wanted.