Foreach Macro on Macros Arguments

Foreach macro on macros arguments

Since you are accepting that the preprocessor has VA_ARGS (in C99, but not in the current C++ standard) you can go with P99. It has exactly what you are asking for: P99_FOR. It works without the crude ()()() syntax from BOOST. The interface is just

P99_FOR(NAME, N, OP, FUNC,...) 

and you can use it with something like

#define P00_SEP(NAME, I, REC, RES) REC; RES
#define P00_VASSIGN(NAME, X, I) X = (NAME)[I]
#define MYASSIGN(NAME, ...) P99_FOR(NAME, P99_NARG(__VA_ARGS__), P00_SEP, P00_VASSIGN, __VA_ARGS__)

MYASSIGN(A, toto, tutu);

FOR_EACH macro with two or more params in call macro

Against my better judgement, I'm going to answer this (because it can be useful in a few rare cases). I modified the code you posted so it requires two parameters (demo):

#include <iostream>

#define EXPAND(x) x
#define FOR_EACH_2(what, delimiter, x, y) what((x), (y))
#define FOR_EACH_4(what, delimiter, x, y, ...)\
what((x), (y)) delimiter \
EXPAND(FOR_EACH_2(what, delimiter, __VA_ARGS__))
#define FOR_EACH_6(what, delimiter, x, y, ...)\
what((x), (y)) delimiter \
EXPAND(FOR_EACH_4(what, delimiter, __VA_ARGS__))

#define FOR_EACH_NARG(...) FOR_EACH_NARG_(__VA_ARGS__, FOR_EACH_RSEQ_N())
#define FOR_EACH_NARG_(...) EXPAND(FOR_EACH_ARG_N(__VA_ARGS__))
#define FOR_EACH_ARG_N(_1, _2, _3, _4, _5, _6, N, ...) N
#define FOR_EACH_RSEQ_N() 6, 5, 4, 3, 2, 1, 0
#define CONCATENATE(x,y) x##y
#define FOR_EACH_(N, what, delimiter, ...) EXPAND(CONCATENATE(FOR_EACH_, N)(what, delimiter, __VA_ARGS__))

#define FOR_EACH(what, delimiter, ...) FOR_EACH_(FOR_EACH_NARG(__VA_ARGS__), what, delimiter, __VA_ARGS__)

void foo(int x, float y) {
std::cout << "foo(" << x << ", " << y << ")\n";
}

int main() {
FOR_EACH(foo, ;, 1, 3.14, 2, 1.41, 3, 1.73);
}

Output is:

foo(1, 3.14)
foo(2, 1.41)
foo(3, 1.73)

You'll have to add additional cases if you want to call foo more than 3 times, which I'll leave as an exercise to the reader.

This can be cleaned up, and should probably be given a different name than FOR_EACH (perhaps something like FOR_EACH_2 to indicate it operates on 2 arguments at a time), which I'll leave as another exercise to the reader.

The reason I'm leaving things as an exercise to the reader is to discourage use of this answer (but not altogether prevent it). If you can't be bothered to clean this up and tailor it to your needs, well then that's on you.

Preprocessor variadic FOR_EACH macro compatible with MSVC++10

Having now grasped exactly how the VC++10 compiler bug works, I was able to come up with such a macro myself, based on the latter part of this answer.

#define EXPAND(x) x
#define FOR_EACH_1(what, x, ...) what(x)
#define FOR_EACH_2(what, x, ...)\
what(x);\
EXPAND(FOR_EACH_1(what, __VA_ARGS__))
#define FOR_EACH_3(what, x, ...)\
what(x);\
EXPAND(FOR_EACH_2(what, __VA_ARGS__))
#define FOR_EACH_4(what, x, ...)\
what(x);\
EXPAND(FOR_EACH_3(what, __VA_ARGS__))
#define FOR_EACH_5(what, x, ...)\
what(x);\
EXPAND(FOR_EACH_4(what, __VA_ARGS__))
#define FOR_EACH_6(what, x, ...)\
what(x);\
EXPAND(FOR_EACH_5(what, __VA_ARGS__))
#define FOR_EACH_7(what, x, ...)\
what(x);\
EXPAND(FOR_EACH_6(what, __VA_ARGS__))
#define FOR_EACH_8(what, x, ...)\
what(x);\
EXPAND(FOR_EACH_7(what, __VA_ARGS__))
#define FOR_EACH_NARG(...) FOR_EACH_NARG_(__VA_ARGS__, FOR_EACH_RSEQ_N())
#define FOR_EACH_NARG_(...) EXPAND(FOR_EACH_ARG_N(__VA_ARGS__))
#define FOR_EACH_ARG_N(_1, _2, _3, _4, _5, _6, _7, _8, N, ...) N
#define FOR_EACH_RSEQ_N() 8, 7, 6, 5, 4, 3, 2, 1, 0
#define CONCATENATE(x,y) x##y
#define FOR_EACH_(N, what, ...) EXPAND(CONCATENATE(FOR_EACH_, N)(what, __VA_ARGS__))
#define FOR_EACH(what, ...) FOR_EACH_(FOR_EACH_NARG(__VA_ARGS__), what, __VA_ARGS__)

Example usage:

#define callMember(o, f) o.f();
#define callMember_o(f) callMember(o, f)
FOR_EACH(callMember_o, doSomething, doSomethingElse);

is the same as

o.doSomething(); o.doSomethingElse();

This solution is similar to that in the linked answer, except that the zero length variadic argument list in FOR_EACH(what, x, ...) when called with one element caused a spurious comma that makes FOR_EACH_NARG count 2 arguments instead of 1 argument, and the EXPAND macro workaround is used.

The bug in VC++10 is that if __VA_ARGS__ is passed to a macro within the definition of a variadic macro, it is evaluated after substitution into the macro, causing multiple comma separated arguments to be treated as one. To get around this you must delay argument evaluation until after __VA_ARGS__ is substituted, by wrapping the macro call in EXPAND, forcing the macro call to be evaluated as a string, substituting __VA_ARGS__ to do so. Only after the substitution into EXPAND is the macro called, by which point the variadic arguments are already substituted.

P.S. I would be grateful if anyone can suggest a method for compactly producing FOR_EACH_N macros for much larger values of N.

How can I invoke a macro with all points in a catersian product of argument sets?

The boost preprocessor library can perform Cartesian products already on preprocessor lists and sequences. You don't specify what preprocessor data types you want to input... assuming that A and B are tuples, and that you have variadics, you can do:

#include <boost/preprocessor/seq/for_each_product.hpp>
#include <boost/preprocessor/seq/to_tuple.hpp>
#include <boost/preprocessor/tuple/to_seq.hpp>

#define EVAL(...) __VA_ARGS__
#define FOO_SEMI_DELIM(R,SEQ_X) EVAL(FOO BOOST_PP_SEQ_TO_TUPLE(SEQ_X));
#define FOO_CARTESIAN(TUP_A,TUP_B) \
BOOST_PP_SEQ_FOR_EACH_PRODUCT \
( FOO_SEMI_DELIM, \
(BOOST_PP_TUPLE_TO_SEQ(TUP_A)) \
(BOOST_PP_TUPLE_TO_SEQ(TUP_B)) \
)

FOO_CARTESIAN((John,Jane),(Smith,Jones,Parker,Peterson))

Since FOO is in all caps, I'm assuming you want to wind up calling FOO as a macro; EVAL here allows you to do this.

You can easily extend this to Cartesian products of higher dimensions.

Is it possible to iterate over arguments in variadic macros?

Here is my homework of the day, it's based on macro tricks and today I particularly learnt about __VA_NARG__ invented by Laurent Deniau. Anyway, the following sample code works up to 8 fields for the sake of clarity. Just extend the code by duplicating if you need more (this is because the preprocessor doesn't feature recursion, as it reads the file only once).

#include <stdio.h>
#include <stddef.h>

struct a
{
int a;
int b;
int c;
};

struct b
{
int a;
int b;
int c;
int d;
};

#define STRINGIZE(arg) STRINGIZE1(arg)
#define STRINGIZE1(arg) STRINGIZE2(arg)
#define STRINGIZE2(arg) #arg

#define CONCATENATE(arg1, arg2) CONCATENATE1(arg1, arg2)
#define CONCATENATE1(arg1, arg2) CONCATENATE2(arg1, arg2)
#define CONCATENATE2(arg1, arg2) arg1##arg2

/* PRN_STRUCT_OFFSETS will print offset of each of the fields
within structure passed as the first argument.
*/
#define PRN_STRUCT_OFFSETS_1(structure, field, ...) printf(STRINGIZE(structure)":"STRINGIZE(field)"-%d\n", offsetof(structure, field));
#define PRN_STRUCT_OFFSETS_2(structure, field, ...)\
printf(STRINGIZE(structure)":"STRINGIZE(field)"-%d\n", offsetof(structure, field));\
PRN_STRUCT_OFFSETS_1(structure, __VA_ARGS__)
#define PRN_STRUCT_OFFSETS_3(structure, field, ...)\
printf(STRINGIZE(structure)":"STRINGIZE(field)"-%d\n", offsetof(structure, field));\
PRN_STRUCT_OFFSETS_2(structure, __VA_ARGS__)
#define PRN_STRUCT_OFFSETS_4(structure, field, ...)\
printf(STRINGIZE(structure)":"STRINGIZE(field)"-%d\n", offsetof(structure, field));\
PRN_STRUCT_OFFSETS_3(structure, __VA_ARGS__)
#define PRN_STRUCT_OFFSETS_5(structure, field, ...)\
printf(STRINGIZE(structure)":"STRINGIZE(field)"-%d\n", offsetof(structure, field));\
PRN_STRUCT_OFFSETS_4(structure, __VA_ARGS__)
#define PRN_STRUCT_OFFSETS_6(structure, field, ...)\
printf(STRINGIZE(structure)":"STRINGIZE(field)"-%d\n", offsetof(structure, field));\
PRN_STRUCT_OFFSETS_5(structure, __VA_ARGS__)
#define PRN_STRUCT_OFFSETS_7(structure, field, ...)\
printf(STRINGIZE(structure)":"STRINGIZE(field)"-%d\n", offsetof(structure, field));\
PRN_STRUCT_OFFSETS_6(structure, __VA_ARGS__)
#define PRN_STRUCT_OFFSETS_8(structure, field, ...)\
printf(STRINGIZE(structure)":"STRINGIZE(field)"-%d\n", offsetof(structure, field));\
PRN_STRUCT_OFFSETS_7(structure, __VA_ARGS__)

#define PRN_STRUCT_OFFSETS_NARG(...) PRN_STRUCT_OFFSETS_NARG_(__VA_ARGS__, PRN_STRUCT_OFFSETS_RSEQ_N())
#define PRN_STRUCT_OFFSETS_NARG_(...) PRN_STRUCT_OFFSETS_ARG_N(__VA_ARGS__)
#define PRN_STRUCT_OFFSETS_ARG_N(_1, _2, _3, _4, _5, _6, _7, _8, N, ...) N
#define PRN_STRUCT_OFFSETS_RSEQ_N() 8, 7, 6, 5, 4, 3, 2, 1, 0

#define PRN_STRUCT_OFFSETS_(N, structure, field, ...) CONCATENATE(PRN_STRUCT_OFFSETS_, N)(structure, field, __VA_ARGS__)

#define PRN_STRUCT_OFFSETS(structure, field, ...) PRN_STRUCT_OFFSETS_(PRN_STRUCT_OFFSETS_NARG(field, __VA_ARGS__), structure, field, __VA_ARGS__)

int main(int argc, char *argv[])
{
PRN_STRUCT_OFFSETS(struct a, a, b, c);
printf("\n");
PRN_STRUCT_OFFSETS(struct b, a, b, c, d);

return 0;
}

which prints out:

struct a:a-0
struct a:b-4
struct a:c-8

struct b:a-0
struct b:b-4
struct b:c-8
struct b:d-12

EDIT: Here is a slightly different version that tries to be more generic. The FOR_EACH(what, ...) macro applies what to every other argument in the variable argument list.

So, you just have to define a macro that takes a single argument like this:

#define DO_STUFF(x) foo(x)

which is going to be applied to every argument in the list.
So, for your typical example you need to hack a bit but it still remains concise:

#define PRN_STRUCT_OFFSETS_(structure, field) printf(STRINGIZE(structure)":"STRINGIZE(field)" - offset = %d\n", offsetof(structure, field));
#define PRN_STRUCT_OFFSETS(field) PRN_STRUCT_OFFSETS_(struct a, field)

And you apply it like this:

FOR_EACH(PRN_STRUCT_OFFSETS, a, b, c);

Finally, a complete sample program:

#include <stdio.h>
#include <stddef.h>

struct a
{
int a;
int b;
int c;
};

#define STRINGIZE(arg) STRINGIZE1(arg)
#define STRINGIZE1(arg) STRINGIZE2(arg)
#define STRINGIZE2(arg) #arg

#define CONCATENATE(arg1, arg2) CONCATENATE1(arg1, arg2)
#define CONCATENATE1(arg1, arg2) CONCATENATE2(arg1, arg2)
#define CONCATENATE2(arg1, arg2) arg1##arg2

#define FOR_EACH_1(what, x, ...) what(x)
#define FOR_EACH_2(what, x, ...)\
what(x);\
FOR_EACH_1(what, __VA_ARGS__);
#define FOR_EACH_3(what, x, ...)\
what(x);\
FOR_EACH_2(what, __VA_ARGS__);
#define FOR_EACH_4(what, x, ...)\
what(x);\
FOR_EACH_3(what, __VA_ARGS__);
#define FOR_EACH_5(what, x, ...)\
what(x);\
FOR_EACH_4(what, __VA_ARGS__);
#define FOR_EACH_6(what, x, ...)\
what(x);\
FOR_EACH_5(what, __VA_ARGS__);
#define FOR_EACH_7(what, x, ...)\
what(x);\
FOR_EACH_6(what, __VA_ARGS__);
#define FOR_EACH_8(what, x, ...)\
what(x);\
FOR_EACH_7(what, __VA_ARGS__);

#define FOR_EACH_NARG(...) FOR_EACH_NARG_(__VA_ARGS__, FOR_EACH_RSEQ_N())
#define FOR_EACH_NARG_(...) FOR_EACH_ARG_N(__VA_ARGS__)
#define FOR_EACH_ARG_N(_1, _2, _3, _4, _5, _6, _7, _8, N, ...) N
#define FOR_EACH_RSEQ_N() 8, 7, 6, 5, 4, 3, 2, 1, 0

#define FOR_EACH_(N, what, x, ...) CONCATENATE(FOR_EACH_, N)(what, x, __VA_ARGS__)
#define FOR_EACH(what, x, ...) FOR_EACH_(FOR_EACH_NARG(x, __VA_ARGS__), what, x, __VA_ARGS__)

#define PRN_STRUCT_OFFSETS_(structure, field) printf(STRINGIZE(structure)":"STRINGIZE(field)" - offset = %d\n", offsetof(structure, field));
#define PRN_STRUCT_OFFSETS(field) PRN_STRUCT_OFFSETS_(struct a, field)

int main(int argc, char *argv[])
{
FOR_EACH(PRN_STRUCT_OFFSETS, a, b, c);
printf("\n");

return 0;
}

How to get name for each argument in variadic macros?

If you can use Boost.Preprocessor, you can do this:

#define PROCESS_ONE_ELEMENT(r, unused, idx, elem) \
BOOST_PP_COMMA_IF(idx) BOOST_PP_STRINGIZE(elem) , " " , elem

#define PRINT_ALL(...) \
print_all(BOOST_PP_SEQ_FOR_EACH_I(PROCESS_ONE_ELEMENT, %%, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__)))

[Live example]

I use %% as a placholder for "unused value."



Related Topics



Leave a reply



Submit