I'm creating a new pattern matching library for C++ and therefore I have to do some advanced macro metaprogramming. I'm stuck on the following error for half a day now, and I'm running out of options. I'd really like it to work, though. Could someone take a look at it?
../../test/macros.cpp:57:16: error: pasting formed ')0', an invalid preprocessing token
ZEN_FOR_EACH(DECLARE_VARS_NUMBERED, foo, bar, baz);
^
../../test/macros.cpp:57:3: error: expected ';' at end of declaration
ZEN_FOR_EACH(DECLARE_VARS_NUMBERED, foo, bar, baz);
^
../../include/zen/macros.h:167:30: note: expanded from macro 'ZEN_FOR_EACH'
#define ZEN_FOR_EACH(m, ...) ZEN_FOR_EACH_WITH(, m, __VA_ARGS__)
^
../../include/zen/macros.h:166:38: note: expanded from macro 'ZEN_FOR_EACH_WITH'
#define ZEN_FOR_EACH_WITH(s, m, ...) ZEN_REPEAT_WITH(s, ZEN_EXPAND(ZEN_VA_LENGTH(__VA_ARGS__)), ZEN_FOR_EACH_IMPL, m, __VA_ARGS__)
^
../../include/zen/macros.h:117:36: note: expanded from macro 'ZEN_REPEAT_WITH'
#define ZEN_REPEAT_WITH(s,n,m,...) ZEN_CONCAT(ZEN_REPEAT_WITH_, n)(s,m,__VA_ARGS__)
^
note: (skipping 1 expansions in backtrace; use -fmacro-backtrace-limit=0 to see all)
../../include/zen/macros.h:67:31: note: expanded from macro 'ZEN_CONCAT_IMPL'
#define ZEN_CONCAT_IMPL(a, b) a ## b
^
<scratch space>:3:1: note: expanded from here
ZEN_REPEAT_WITH_3
^
../../include/zen/macros.h:100:38: note: expanded from macro 'ZEN_REPEAT_WITH_3'
#define ZEN_REPEAT_WITH_3(s,m,...) m(0,__VA_ARGS__) s m(1,__VA_ARGS__) s m(2,__VA_ARGS__)
^
../../test/macros.cpp:57:16: error: pasting formed ')1', an invalid preprocessing token
ZEN_FOR_EACH(DECLARE_VARS_NUMBERED, foo, bar, baz);
^
../../test/macros.cpp:57:3: error: expected ';' at end of declaration
ZEN_FOR_EACH(DECLARE_VARS_NUMBERED, foo, bar, baz);
^
../../include/zen/macros.h:167:30: note: expanded from macro 'ZEN_FOR_EACH'
#define ZEN_FOR_EACH(m, ...) ZEN_FOR_EACH_WITH(, m, __VA_ARGS__)
^
../../include/zen/macros.h:166:38: note: expanded from macro 'ZEN_FOR_EACH_WITH'
#define ZEN_FOR_EACH_WITH(s, m, ...) ZEN_REPEAT_WITH(s, ZEN_EXPAND(ZEN_VA_LENGTH(__VA_ARGS__)), ZEN_FOR_EACH_IMPL, m, __VA_ARGS__)
^
../../include/zen/macros.h:117:36: note: expanded from macro 'ZEN_REPEAT_WITH'
#define ZEN_REPEAT_WITH(s,n,m,...) ZEN_CONCAT(ZEN_REPEAT_WITH_, n)(s,m,__VA_ARGS__)
^
note: (skipping 1 expansions in backtrace; use -fmacro-backtrace-limit=0 to see all)
../../include/zen/macros.h:67:31: note: expanded from macro 'ZEN_CONCAT_IMPL'
#define ZEN_CONCAT_IMPL(a, b) a ## b
^
<scratch space>:3:1: note: expanded from here
ZEN_REPEAT_WITH_3
^
../../include/zen/macros.h:100:57: note: expanded from macro 'ZEN_REPEAT_WITH_3'
#define ZEN_REPEAT_WITH_3(s,m,...) m(0,__VA_ARGS__) s m(1,__VA_ARGS__) s m(2,__VA_ARGS__)
^
../../test/macros.cpp:57:16: error: pasting formed ')2', an invalid preprocessing token
ZEN_FOR_EACH(DECLARE_VARS_NUMBERED, foo, bar, baz);
^
../../test/macros.cpp:57:3: error: expected ';' at end of declaration
ZEN_FOR_EACH(DECLARE_VARS_NUMBERED, foo, bar, baz);
^
../../include/zen/macros.h:167:30: note: expanded from macro 'ZEN_FOR_EACH'
#define ZEN_FOR_EACH(m, ...) ZEN_FOR_EACH_WITH(, m, __VA_ARGS__)
^
../../include/zen/macros.h:166:38: note: expanded from macro 'ZEN_FOR_EACH_WITH'
#define ZEN_FOR_EACH_WITH(s, m, ...) ZEN_REPEAT_WITH(s, ZEN_EXPAND(ZEN_VA_LENGTH(__VA_ARGS__)), ZEN_FOR_EACH_IMPL, m, __VA_ARGS__)
^
../../include/zen/macros.h:117:36: note: expanded from macro 'ZEN_REPEAT_WITH'
#define ZEN_REPEAT_WITH(s,n,m,...) ZEN_CONCAT(ZEN_REPEAT_WITH_, n)(s,m,__VA_ARGS__)
^
note: (skipping 1 expansions in backtrace; use -fmacro-backtrace-limit=0 to see all)
../../include/zen/macros.h:67:31: note: expanded from macro 'ZEN_CONCAT_IMPL'
#define ZEN_CONCAT_IMPL(a, b) a ## b
^
<scratch space>:3:1: note: expanded from here
ZEN_REPEAT_WITH_3
^
../../include/zen/macros.h:100:76: note: expanded from macro 'ZEN_REPEAT_WITH_3'
#define ZEN_REPEAT_WITH_3(s,m,...) m(0,__VA_ARGS__) s m(1,__VA_ARGS__) s m(2,__VA_ARGS__)
The following is the evilness that I came up with:
#define ZEN_FOR_EACH_IMPL(i, m, ...) m(i, ZEN_GET_VA_ARG(i,__VA_ARGS__))
#define ZEN_FOR_EACH_WITH(s, m, ...) ZEN_REPEAT_WITH(s, ZEN_VA_LENGTH(__VA_ARGS__), ZEN_FOR_EACH_IMPL, m, __VA_ARGS__)
#define ZEN_FOR_EACH(m, ...) ZEN_FOR_EACH_WITH(, m, __VA_ARGS__)
It should allow to perform an indexed traversal on a list of arguments with as callback another function macro, like so:
#define DECLARE_VARS_NUMBERED(i, name) int name ## i = 42;
ZEN_FOR_EACH(DECLARE_VARS_NUMBERED, foo, bar, baz);
Will generate the following code:
int foo0 = 42;
int bar1 = 42;
int baz2 = 42;
This example is not what I'm planning to use it for, but it should make clear what the macro does.
These are some additional helper macros. Most of them were auto-generated. Their meaning should be straightforward. I've tested them on some simple use-cases, and they worked as expected:
#define ZEN_CONCAT(a, b) ZEN_CONCAT_IMPL(a, b)
#define ZEN_CONCAT_IMPL(a, b) a ## b
#define ZEN_REPEAT_WITH_0(s,m,...)
#define ZEN_REPEAT_WITH_1(s,m,...) m(0,__VA_ARGS__)
#define ZEN_REPEAT_WITH_2(s,m,...) m(0,__VA_ARGS__) s m(1,__VA_ARGS__)
#define ZEN_REPEAT_WITH_3(s,m,...) m(0,__VA_ARGS__) s m(1,__VA_ARGS__) s m(2,__VA_ARGS__)
#define ZEN_REPEAT_WITH_4(s,m,...) m(0,__VA_ARGS__) s m(1,__VA_ARGS__) s m(2,__VA_ARGS__) s m(3,__VA_ARGS__)
#define ZEN_REPEAT_WITH_5(s,m,...) m(0,__VA_ARGS__) s m(1,__VA_ARGS__) s m(2,__VA_ARGS__) s m(3,__VA_ARGS__) s m(4,__VA_ARGS__)
#define ZEN_REPEAT_WITH_6(s,m,...) m(0,__VA_ARGS__) s m(1,__VA_ARGS__) s m(2,__VA_ARGS__) s m(3,__VA_ARGS__) s m(4,__VA_ARGS__) s m(5,__VA_ARGS__)
#define ZEN_REPEAT_WITH_7(s,m,...) m(0,__VA_ARGS__) s m(1,__VA_ARGS__) s m(2,__VA_ARGS__) s m(3,__VA_ARGS__) s m(4,__VA_ARGS__) s m(5,__VA_ARGS__) s m(6,__VA_ARGS__)
#define ZEN_REPEAT_WITH_8(s,m,...) m(0,__VA_ARGS__) s m(1,__VA_ARGS__) s m(2,__VA_ARGS__) s m(3,__VA_ARGS__) s m(4,__VA_ARGS__) s m(5,__VA_ARGS__) s m(6,__VA_ARGS__) s m(7,__VA_ARGS__)
#define ZEN_REPEAT_WITH_9(s,m,...) m(0,__VA_ARGS__) s m(1,__VA_ARGS__) s m(2,__VA_ARGS__) s m(3,__VA_ARGS__) s m(4,__VA_ARGS__) s m(5,__VA_ARGS__) s m(6,__VA_ARGS__) s m(7,__VA_ARGS__) s m(8,__VA_ARGS__)
#define ZEN_REPEAT_WITH(s,n,m,...) ZEN_CONCAT(ZEN_REPEAT_WITH_, n)(s,m,__VA_ARGS__)
#define ZEN_REPEAT(n,m,...) ZEN_REPEAT_WITH(,n,m,__VA_ARGS__)
#define ZEN_GET_VA_ARG_0(arg0,...) arg0
#define ZEN_GET_VA_ARG_1(arg0, arg1,...) arg1
#define ZEN_GET_VA_ARG_2(arg0, arg1, arg2,...) arg2
#define ZEN_GET_VA_ARG_3(arg0, arg1, arg2, arg3,...) arg3
#define ZEN_GET_VA_ARG_4(arg0, arg1, arg2, arg3, arg4,...) arg4
#define ZEN_GET_VA_ARG_5(arg0, arg1, arg2, arg3, arg4, arg5,...) arg5
#define ZEN_GET_VA_ARG_6(arg0, arg1, arg2, arg3, arg4, arg5, arg6,...) arg6
#define ZEN_GET_VA_ARG_7(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7,...) arg7
#define ZEN_GET_VA_ARG_8(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8,...) arg8
#define ZEN_GET_VA_ARG_9(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9,...) arg9
#define ZEN_GET_VA_ARG(n,...) ZEN_CONCAT(ZEN_GET_VA_ARG_, n)(__VA_ARGS__)
I really don't get the error message. I'm guessing it has something to do with the macros being expanded before they're passed along but trying some modifications did not yield anything significant.
I've found this answer but I'm unsure how it applies to my use case.