4

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++.

Yakov Galka
  • 61,035
  • 13
  • 128
  • 192

1 Answers1

3

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.

Johannes Schaub - litb
  • 466,055
  • 116
  • 851
  • 1,175