Consider the following user-style x-macro:
#define PRIMES_X(func) \
func(2) \
func(3) \
func(5) \
func(7)
We can use this to expand a passed-in macro func
repeatedly with the first four primes. For example:
#define MAKE_FUNC(num) void foo ## num();
PRIMES_X(MAKE_FUNC)
Would declare the void-returning functions foo2()
, foo3()
, foo5()
and foo7()
.
So far, so good.
Let's say that I know want to create a related x-macro, which calls its argument not with the bare primes 2
, 3
, ... but with some token derived from it, such as the function names above. That is, I want this:
#define PRIMES_FOO_X(func) \
func(foo2) \
func(foo3) \
func(foo5) \
func(foo7)
but without actually writing it all out (indeed, it would get out of sync the moment PRIMES_X
changes.
What I want is a way define PRIMES_FOO_X
in terms of PRIMES_X
. I can almost get there, e.g.:
#define FOO_ADAPT(num) func(foo ## num)
#define PRIMES_FOO_X(f) PRIMES_X(FOO_ADAPT)
In this case, PRIMES_FOO_X
expands to:
func(foo2) \
func(foo3) \
func(foo5) \
func(foo7)
... which looks right, but the func
here isn't the passed arg, but just plain token func
since FOO_ADAPT
doesn't have an argument called func
, only PRIMES_FOO_X(func)
does (and it doesn't use it).
I can't figure out a way to make this work.
A key observation... given this:
#define PRIMES_X(func) \
func(2) \
func(3) \
func(5) \
func(7)
PRIMES_X()
expands to (2) (3) (5) (7)
, which in terms of CPP metaprogramming is a sequence data structure. This in mind, let's start going backwards. You want something like this:
#define PRIMES_FOO_X(func) \
/* something that expands to: func(foo2) func(foo3) func(foo5) func(foo7) */
...and you want foo2
, foo3
, foo5
, foo7
to come from PRIMES_X
expansion. Obviously then 2
becomes foo2
, 3
becomes foo3
, etc; so let's assume such becomings happen according to a macro called FOOIDENT_OF
. Then in PRIMES_FOO_X
you need to call func
on (FOOIDENT_OF(2))
, etc; that is, you want something more precisely like this:
#define PRIMES_FOO_X(func) \
/* something that expands to: \
* func(FOOIDENT_OF(2)) func(FOOIDENT_OF(3)) \
* func(FOOIDENT_OF(5)) func(FOOIDENT_OF(7)) */
Combining the two ideas, the elements we have are:
func
, the operation to apply in the derived X-macroFOOIDENT_OF
, the operation that transforms each X-macro argument list to the new formPRIMES_X()
, a sequence of all of the argument listsThis is possible, and even a bit easy to do if we use boost preprocessor's sequence.
#include <boost/preprocessor/seq.hpp>
#define PAIR_ELEMENT_1(A,B) A
#define PAIR_ELEMENT_2(A,B) B
#define PAIR_XFORM_MACRO(r, data, elem) \
PAIR_ELEMENT_1 data ( PAIR_ELEMENT_2 data (elem) )
#define PAIR_XFORM(PAIR_, SEQ_) \
BOOST_PP_SEQ_FOR_EACH(PAIR_XFORM_MACRO, PAIR_, SEQ_)
Here I have a PAIR_XFORM
that takes a 2-tuple ("pair") of macros, and applies both of them to each element of a sequence. IOW, PAIR_XFORM((func, FOOIDENT_OF), PRIMES_X())
generates our target. Now all we need is to gen up the new X-macro and make the inner transform macro:
#define FOOIDENT_OF(N) foo##N
#define PRIMES_FOO_X(func) PAIR_XFORM((func, FOOIDENT_OF), PRIMES_X())
Here is what it looks like on stacked-crooked.