如何将宏展开的结果分离为不同的参数?

发布于 2024-11-01 04:29:47 字数 668 浏览 0 评论 0原文

我正在编写一些 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

踏雪无痕 2024-11-08 04:29:47

我认为如果遇到 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 参数宏。

您可以这样做

#define EVAL(X) X
#define ITERATION(args) ITERATION_IMPL EVAL((hello, args(), world))

,这将采用 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 应该是

#define ITERATION(args) EVAL(ITERATION_IMPL EVAL((hello, args(), world)))

当外部 EVALXITERATION_IMPL EVAL((hello, args(), world)) 替换时,它会重新扫描并生成 ITERATION_IMPL (hello, a, b, world) 以调用 EVAL。然后它再次重新扫描 ITERATION 的调用并生成您真正想要的序列。

I think if ITERATION(ARGS) is encountered, it takes ITERATION_IMPL(hello, args(), world), replaces args with ARGS, and then rescans. ITERATION_IMPL(hello, ARGS(), world) is an invocation of ITERATION_IMPL. Therefor, it takes ((p1),(p2),(p3),(p4)), and replaces p2 by ARGS() (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

#define EVAL(X) X
#define ITERATION(args) ITERATION_IMPL EVAL((hello, args(), world))

That would take X, substitute (hello, ARGS(), world), and then rescan, causing ARGS() to be replaced by a, b. The resulting token string ITERATION_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 string ITERATION_IMPL (hello, a, b, world). I think that's because when it rescans after calling ITERATION, it replaces IERATION_IMPL EVAL((hello, ARGS(), world)) by ITERATION_IMPL (hello, a, b, wold). Then it would need another scan to notice that it can now invoke ITERATION_IMPL with those arguments. So ITERATION should be

#define ITERATION(args) EVAL(ITERATION_IMPL EVAL((hello, args(), world)))

When X for the outer EVAL is substituted by ITERATION_IMPL EVAL((hello, args(), world)), it rescans and yields ITERATION_IMPL (hello, a, b, world) for the invocation of EVAL. Then it rescans again for the invocation of ITERATION and yields the sequence you really wanted.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文