I've seen a few questions asking for a variation on a variadic FOR_EACH macro. However unfortunately the answers provided are incompatible with VC++10 due to it expanding __VA_ARGS __ as one argument when passed to another macro. Please could someone provide a C++11 compliant (thus forward-compatible) version that still works with VC++10. Perhaps using the "workaround" that is often mentioned, #define EXPAND(x) x, however I don't know where to put this in order to get, for example, the latter generalised part of this answer to work in VC++10.
To clarify, the intended behaviour is for FOR_EACH(x, a, b, ...) to produce x(a) x(b), ..., where x is another macro.
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.
I wrote a python code to generate for_each macro for N times, based on Dylan's answer.
below is the code:
from builtins import *
# number of generated for_each cases.
iter_max = 19
# override this with your own!
prefix = "MY_" # define your own macro prefix, which ends with under_score if not empty.
internal_prefix = "internal_"
# CODE ------------------------------------------------------------------------------------------------------
INTERNAL_ = f"{internal_prefix}{prefix}"
fmt_numstr = "{}" # f"{{:0>{max_digit}}}"
EXPAND = f"{INTERNAL_}EXPAND"
FOR_EACH = f"{INTERNAL_}FOR_EACH_"
FOR_EACH_N = f"{FOR_EACH}{fmt_numstr}"
OUT = "#pragma once\n"
OUT += f"#define {EXPAND}(x) x\n"
OUT += f"#define {FOR_EACH_N.format(1)}(what, x, ...) what(x)\n"
for i in range(2, iter_max + 1):
OUT += f"#define {FOR_EACH_N.format(i)}(what, x, ...) " \
f"what(x);" \
f"{EXPAND}({FOR_EACH_N.format(i - 1)}(what, __VA_ARGS__))\n"
FOR_EACH_NARG = f"{INTERNAL_}FOR_EACH_NARG"
FOR_EACH_RSEQ_N = f"{INTERNAL_}FOR_EACH_RSEQ_N"
FOR_EACH_ARG_N = f"{INTERNAL_}FOR_EACH_ARG_N"
OUT += f"#define {FOR_EACH_NARG}(...) {FOR_EACH_NARG}_(__VA_ARGS__, {FOR_EACH_RSEQ_N}())\n"
OUT += f"#define {FOR_EACH_NARG}_(...) {EXPAND}({FOR_EACH_ARG_N}(__VA_ARGS__))\n"
underscore_sequence = ""
inverse_sequence = ""
for i in range(1, iter_max + 1):
underscore_sequence += f"_{i}{',' if i < iter_max else ''}"
for i in range(0, iter_max + 1):
inverse_sequence += f"{fmt_numstr}{',' if i < iter_max else ''} ".format(iter_max - i)
OUT += f"#define {FOR_EACH_ARG_N}({underscore_sequence}, N, ...) N\n"
OUT += f"#define {FOR_EACH_RSEQ_N}() {inverse_sequence}\n"
CONCATENATE = f"{INTERNAL_}CONCATENATE"
OUT += f"#define {CONCATENATE}(x,y) x##y\n"
INTERNAL_FOR_EACH = f"{INTERNAL_}FOR_EACH_"
OUT += f"#define {INTERNAL_FOR_EACH}(N, what, ...) {EXPAND}({CONCATENATE}({FOR_EACH}, N)(what, __VA_ARGS__))\n"
OUT += f"#define {prefix}FOR_EACH(what, ...) {INTERNAL_FOR_EACH}({FOR_EACH_NARG}(__VA_ARGS__), what, __VA_ARGS__)\n"
print(OUT)
Execution result is:
#pragma once
#define internal_MY_EXPAND(x) x
#define internal_MY_FOR_EACH_1(what, x, ...) what(x)
#define internal_MY_FOR_EACH_2(what, x, ...) what(x);internal_MY_EXPAND(internal_MY_FOR_EACH_1(what, __VA_ARGS__))
#define internal_MY_FOR_EACH_3(what, x, ...) what(x);internal_MY_EXPAND(internal_MY_FOR_EACH_2(what, __VA_ARGS__))
#define internal_MY_FOR_EACH_4(what, x, ...) what(x);internal_MY_EXPAND(internal_MY_FOR_EACH_3(what, __VA_ARGS__))
#define internal_MY_FOR_EACH_5(what, x, ...) what(x);internal_MY_EXPAND(internal_MY_FOR_EACH_4(what, __VA_ARGS__))
#define internal_MY_FOR_EACH_6(what, x, ...) what(x);internal_MY_EXPAND(internal_MY_FOR_EACH_5(what, __VA_ARGS__))
#define internal_MY_FOR_EACH_7(what, x, ...) what(x);internal_MY_EXPAND(internal_MY_FOR_EACH_6(what, __VA_ARGS__))
#define internal_MY_FOR_EACH_8(what, x, ...) what(x);internal_MY_EXPAND(internal_MY_FOR_EACH_7(what, __VA_ARGS__))
#define internal_MY_FOR_EACH_9(what, x, ...) what(x);internal_MY_EXPAND(internal_MY_FOR_EACH_8(what, __VA_ARGS__))
#define internal_MY_FOR_EACH_10(what, x, ...) what(x);internal_MY_EXPAND(internal_MY_FOR_EACH_9(what, __VA_ARGS__))
#define internal_MY_FOR_EACH_11(what, x, ...) what(x);internal_MY_EXPAND(internal_MY_FOR_EACH_10(what, __VA_ARGS__))
#define internal_MY_FOR_EACH_12(what, x, ...) what(x);internal_MY_EXPAND(internal_MY_FOR_EACH_11(what, __VA_ARGS__))
#define internal_MY_FOR_EACH_13(what, x, ...) what(x);internal_MY_EXPAND(internal_MY_FOR_EACH_12(what, __VA_ARGS__))
#define internal_MY_FOR_EACH_14(what, x, ...) what(x);internal_MY_EXPAND(internal_MY_FOR_EACH_13(what, __VA_ARGS__))
#define internal_MY_FOR_EACH_15(what, x, ...) what(x);internal_MY_EXPAND(internal_MY_FOR_EACH_14(what, __VA_ARGS__))
#define internal_MY_FOR_EACH_16(what, x, ...) what(x);internal_MY_EXPAND(internal_MY_FOR_EACH_15(what, __VA_ARGS__))
#define internal_MY_FOR_EACH_17(what, x, ...) what(x);internal_MY_EXPAND(internal_MY_FOR_EACH_16(what, __VA_ARGS__))
#define internal_MY_FOR_EACH_18(what, x, ...) what(x);internal_MY_EXPAND(internal_MY_FOR_EACH_17(what, __VA_ARGS__))
#define internal_MY_FOR_EACH_19(what, x, ...) what(x);internal_MY_EXPAND(internal_MY_FOR_EACH_18(what, __VA_ARGS__))
#define internal_MY_FOR_EACH_NARG(...) internal_MY_FOR_EACH_NARG_(__VA_ARGS__, internal_MY_FOR_EACH_RSEQ_N())
#define internal_MY_FOR_EACH_NARG_(...) internal_MY_EXPAND(internal_MY_FOR_EACH_ARG_N(__VA_ARGS__))
#define internal_MY_FOR_EACH_ARG_N(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19, N, ...) N
#define internal_MY_FOR_EACH_RSEQ_N() 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0
#define internal_MY_CONCATENATE(x,y) x##y
#define internal_MY_FOR_EACH_(N, what, ...) internal_MY_EXPAND(internal_MY_CONCATENATE(internal_MY_FOR_EACH_, N)(what, __VA_ARGS__))
#define MY_FOR_EACH(what, ...) internal_MY_FOR_EACH_(internal_MY_FOR_EACH_NARG(__VA_ARGS__), what, __VA_ARGS__)
You may customize macro prefix and internal prefixes for your own use.
Related
In order to nicely fix https://github.com/ned14/outcome/issues/244#issuecomment-774181015, I want to know if it is possible to detect whether a token sequence is present within a C preprocessor macro argument?
#define OUTCOME_TRY_GLUE2(x, y) x##y
#define OUTCOME_TRY_GLUE(x, y) OUTCOME_TRY_GLUE2(x, y)
#define OUTCOME_TRY_UNIQUE_NAME OUTCOME_TRY_GLUE(unique, __COUNTER__)
#define OUTCOME_TRYV2_SUCCESS_LIKELY(unique, ...) \
auto &&unique = (__VA_ARGS__)
#define OUTCOME_TRY2_SUCCESS_LIKELY(unique, v, ...) \
OUTCOME_TRYV2_SUCCESS_LIKELY(unique, __VA_ARGS__); \
v = std::move(unique).value()
#define OUTCOME_TRYA(v, ...) OUTCOME_TRY2_SUCCESS_LIKELY(OUTCOME_TRY_UNIQUE_NAME, v, __VA_ARGS__)
/* I'd like this to generate:
auto unique0 = (expr); auto x = std::move(unique0).value();
*/
OUTCOME_TRYA(auto x, expr);
/* I'd like this to generate:
auto &&unique1 = (expr); auto &&x = std::move(unique1).value();
*/
OUTCOME_TRYA(auto &&x, expr);
(https://godbolt.org/z/MW74cG may be more useful)
What one needs to achieve here is detection of && within the expansion of the v macro argument, but not if it is nested within ()<>".
Other answers on Stackoverflow can find a string within a C preprocessor macro argument, however those techniques can't work here because macro token paste of STRING_ ## && isn't legal. This level of C preprocessor hackery is beyond my capabilities, so I ask Stackoverflow. Thanks in advance for any help.
What one needs to achieve here is detection of && within the expansion of the v macro argument, but not if it is nested within ()<>".
No, it is not possible. I suggest separating the type from the name in a separate argument.
OUTCOME_TRYA_NEW(auto, x, expr);
OUTCOME_TRYA_NEW(auto &&, x, expr);
You could move the detection to runtime with stringify, like:
#define OUTCOME_TRYA(v, ...) \
if constexpr (your_constexpr_strstr(#v, "&&")) { \
/* do stuff with `auto &&` here */ \
} else { \
/* do stuff with `auto` here */ \
}
(or I think also with some std::is_same(decltype(v)....) stuff), but as you want to declare variables in the macro expansion, I think that's not helpful.
Another way you could use is to delay the expansion of first argument to later phase so you could overload it on number of arguments, like so:
// Add a comma. But later.
#define OUTCOME_REF(name) &&, name
#define OUTCOME_TRYA_CHOOSE_1(name, ...) \
auto unique0 = (__VA_ARGS__); name = std::move(unique0).value();
#define OUTCOME_TRYA_CHOOSE_2_IN(name, ...) \
auto &&unique1 = (__VA_ARGS__); name = std::move(unique1).value();
#define OUTCOME_TRYA_CHOOSE_2(name, ...) \
OUTCOME_TRYA_CHOOSE_2_IN(name __VA_ARGS__)
// ^^^^^^ I have no idea why it works without a comma, but it does. It's scary.
#define OUTCOME_TRYA_CHOOSE_N(_1,_2,N,...) \
OUTCOME_TRYA_CHOOSE_##N
#define OUTCOME_TRYA_CHOOSE(...) \
OUTCOME_TRYA_CHOOSE_N(__VA_ARGS__,2,1)
#define OUTCOME_TRYA(name, ...) \
OUTCOME_TRYA_CHOOSE(name)(name, __VA_ARGS__)
// ^^^^ - overload on number of arguments in expansion of first parameter
OUTCOME_TRYA(auto x, expr1) // auto unique0 = (expr1); auto x = std::move(unique0).value();
OUTCOME_TRYA(auto OUTCOME_REF(x), expr2) // auto &&unique1 = (expr2); auto && x = std::move(unique1).value();
In similar fashion you could refactor your interface seamlessly to:
#define UNPACK(...) __VA_ARGS__
#define OUTCOME_TRYA_CHOOSE_1(name, nameunpacked, ...) \
auto unique0 = (__VA_ARGS__); name = std::move(unique0).value();
#define OUTCOME_TRYA_CHOOSE_2_IN(name1, name2, ...) \
auto &&unique1 = (__VA_ARGS__); name1 name2 = std::move(unique1).value();
#define OUTCOME_TRYA_CHOOSE_2(name, nameunpacked, ...) \
OUTCOME_TRYA_CHOOSE_2_IN(nameunpacked, __VA_ARGS__)
#define OUTCOME_TRYA_CHOOSE_N(_1,_2,_3,N,...) \
OUTCOME_TRYA_CHOOSE_##N
#define OUTCOME_TRYA_CHOOSE(n, ...) \
OUTCOME_TRYA_CHOOSE_N(n, __VA_ARGS__, 2, 1)
#define OUTCOME_TRYA(name, ...) \
OUTCOME_TRYA_CHOOSE(name, UNPACK name)(name, UNPACK name, __VA_ARGS__)
OUTCOME_TRYA(auto x, expr1, expr2)
OUTCOME_TRYA((auto &&, x), expr3, expr4)
The above looks nice and allows for the current interface to stay. The trick is in OUTCOME_TRYA_CHOOSE(name, UNPACK name) - when name is (something, something), then OUTCOME_TRYA_CHOOSE_N is passed 3 arguments, if it's not, then 2 arguments are passed - which can be then overloaded on number of arguments. So it effectively overloads if the input contains braces with a comma inside.
I don't suppose you know of a way to achieve OUTCOME_TRYV((auto &&), expr1, expr2)
Meh ;p . Add a comma when unpacking, effectively shifting overloads to one more.
#define UNPACK_ADD_COMMA(...) ,__VA_ARGS__
#define OUTCOME_TRYA_CHOOSE_1(name, nameunpacked, ...) \
auto unique0 = (__VA_ARGS__); name = std::move(unique0).value();
#define OUTCOME_TRYA_CHOOSE_2_IN(name1, ...) \
OCH_MY_GOD()
#define OUTCOME_TRYA_CHOOSE_3_IN(name1, name2, ...) \
auto &&unique1 = (__VA_ARGS__); name1 name2 = std::move(unique1).value();
#define OUTCOME_TRYA_CHOOSE_2(name, nameunpacked, ...) \
OUTCOME_TRYA_CHOOSE_2_IN(nameunpacked, __VA_ARGS__)
#define OUTCOME_TRYA_CHOOSE_3(name, ignore, nameunpacked, ...) \
OUTCOME_TRYA_CHOOSE_3_IN(nameunpacked, __VA_ARGS__)
#define OUTCOME_TRYA_CHOOSE_N(_1,_2,_3,_4,N,...) \
OUTCOME_TRYA_CHOOSE_##N
#define OUTCOME_TRYA_CHOOSE_IN(n, ...) \
OUTCOME_TRYA_CHOOSE_N(n, __VA_ARGS__, 3, 2, 1)
#define OUTCOME_TRYA_CHOOSE(n, ...) \
OUTCOME_TRYA_CHOOSE_IN(n, __VA_ARGS__)
#define OUTCOME_TRYA(name, ...) \
OUTCOME_TRYA_CHOOSE(name, UNPACK_ADD_COMMA name)(name, UNPACK_ADD_COMMA name, __VA_ARGS__)
OUTCOME_TRYA(auto x, expr1, expr2)
OUTCOME_TRYA((auto &&, x), expr3, expr4)
OUTCOME_TRYA((auto &&), expr3, expr4)
Trying to get this working in VS2013 (see Variadic macro trick and C++ preprocessor __VA_ARGS__ number of arguments).
It's not a duplicate afaik (versions posted elsewhere only work with GCC).
Any ideas what's wrong with this? I'm almost there...
#define _EXPAND(x) x
#define _VA_NARGS_IMPL(_1_, _2_, _3_, _4_, _5_, N, ...) N
#define _VA_NARGS_IMPL2(...) _EXPAND(_VA_NARGS_IMPL(__VA_ARGS__, 4, 3, 2, 1, 0))
#define _PUSH_X_FRONT(...) X, __VA_ARGS__
/*
Returns the number of arguments specified.
#ifndef _MSC_VER
#define VA_NARGS(...) _VA_NARGS_IMPL2(X,##__VA_ARGS__)
*/
#define VA_NARGS(...) _VA_NARGS_IMPL2(_PUSH_X_FRONT(__VA_ARGS__))
// testing is gewd
static_assert(VA_NARGS() == 0, "VA_NARGS() failed for 0 arguments");
static_assert(VA_NARGS(one, two, three, four) == 4, "VA_NARGS() failed for 4 arguments");
#define _VARARG_IMPL2(N, Macro, ...) Macro##N(__VA_ARGS__)
#define _VARARG_IMPL(N, Macro, ...) _VARARG_IMPL2(N, Macro, __VA_ARGS__)
// Helper function for variadic macros with per-argument processing.
#define VARARG(Macro, ...) _VARARG_IMPL(VA_NARGS(__VA_ARGS__), Macro, __VA_ARGS__)
#define _Quote1(x) #x
#define _Quote2(x, ...) #x, _Quote1(__VA_ARGS__)
#define _Quote3(x, ...) #x, _Quote2(__VA_ARGS__)
#define _Quote4(x, ...) #x, _Quote3(__VA_ARGS__)
// Treat each argument as a string literal, encompassing in quotes.
#define Quote(...) VARARG(_Quote, __VA_ARGS__)
Question:
constexpr char *a[] = { Quote(a, b) };
// WHY does the above produce {"a, b"} with msvc?
// The following produces {"a", "b"} as expected
constexpr char *a[] = { _Quote2(s, c) };
It is difficult to make a real variadic macro to work in VS2013. I had something done to expand a macro to be interpreted on it's own as a new macro. The key is to make multiple level macros. It is a lot to code but for given sample it will work.
#define InitialMacro (argument1, argument2) \
DetailedMacro(argument1, argument2, argument1##_description, argument2##_description)
#define DetailedMacro (argument1, argument2, argument3, argument4) \
L#argument1 \
L#argument2 \
L#argument3 \
L#argument4
The ideea presented here is to implement enough macros to cover all your requirement in the number of parameters nedeed. Also you can forward/update macro with aditional items on the way.
Basically first macro in this example append to the second and third transmitted parameters the suffix _description resulting in another macro that will get interpreted as a macro and it will be expanded in DetailedMacro.
You could also take a look at this: msvc variadic macro expansion
I am programmatically generating C++ code. Frequently I have to output linked lists of the following form,
PTR(new List(a,PTR(new List(NULL,NULL))))
PTR(new List(a, PTR(new List(b,PTR(new List(NULL,NULL))))))
As the size of the lists grow generated code gets uglier I was wondering is it possible to define a variadic macro of the form,
LIST(a)
LIST(a,b)
That would expand to code in the first form.
Here's one way using Boost.Preprocessor, which doesn't depend on any other part of Boost:
#include <boost/preprocessor.hpp>
#define FOR_EACH_OP(r, data, elem) PTR(new List(elem,
#define DOUBLE_RPAREN(...) ))
#define LIST(...) LIST_I(BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__))
#define LIST_I(seq) \
BOOST_PP_SEQ_FOR_EACH(FOR_EACH_OP, /*empty*/, seq) \
PTR(new List(NULL,NULL)) \
BOOST_PP_REPEAT(BOOST_PP_SEQ_SIZE(seq), DOUBLE_RPAREN, /*empty*/)
LIST(a) // PTR(new List(a, PTR(new List(NULL,NULL)) ))
LIST(a,b) // PTR(new List(a, PTR(new List(b, PTR(new List(NULL,NULL)) )) ))
LIST simply turns the arguments into a "PP sequence", which provides a convenient FOR_EACH. For each argument, the left part is built up. Then the NULL part is added. Finally, matching right parentheses are added according to how many arguments were given.
Disclaimer: LIST() will not work as expected due to that being a call with one (empty) argument.
If you're really allergic to Boost, you can make simplified versions of these. For example, one way to support up to four arguments:
#define CAT(_0, _1) CAT_I(_0, _1)
#define CAT_I(_0, _1) _0##_1
#define ARG5(_0, _1, _2, _3, _4, ...) _4
#define NARGS(...) ARG5(__VA_ARGS__, 4, 3, 2, 1,)
#define OVERLOAD(prefix, ...) CAT(prefix, NARGS(__VA_ARGS__))
#define ELEM(i, ...) CAT(ELEM_, i)(__VA_ARGS__,)
#define ELEM_0(_0, ...) _0
#define ELEM_1(_0, _1, ...) _1
#define ELEM_2(_0, _1, _2, ...) _2
#define ELEM_3(_0, _1, _2, _3, ...) _3
#define FOR_EACH(macro, ...) OVERLOAD(FOR_EACH_, __VA_ARGS__)(macro, __VA_ARGS__)
#define FOR_EACH_1(macro, ...) macro(ELEM(0, __VA_ARGS__))
#define FOR_EACH_2(macro, ...) FOR_EACH_1(macro, __VA_ARGS__) macro(ELEM(1, __VA_ARGS__))
#define FOR_EACH_3(macro, ...) FOR_EACH_2(macro, __VA_ARGS__) macro(ELEM(2, __VA_ARGS__))
#define FOR_EACH_4(macro, ...) FOR_EACH_3(macro, __VA_ARGS__) macro(ELEM(3, __VA_ARGS__))
#define REPEAT(n, macro) CAT(REPEAT_, n)(macro)
#define REPEAT_1(macro) macro()
#define REPEAT_2(macro) REPEAT_1(macro) macro()
#define REPEAT_3(macro) REPEAT_2(macro) macro()
#define REPEAT_4(macro) REPEAT_3(macro) macro()
#define FOR_EACH_MACRO(elem) PTR(new List(elem,
#define DOUBLE_RPAREN() ))
#define LIST(...) LIST_I(NARGS(__VA_ARGS__), __VA_ARGS__)
#define LIST_I(n, ...) \
FOR_EACH(FOR_EACH_MACRO, __VA_ARGS__) \
PTR(new List(NULL,NULL)) \
REPEAT(n, DOUBLE_RPAREN)
LIST(a) // PTR(new List(a, PTR(new List(NULL,NULL)) ))
LIST(a,b) // PTR(new List(a, PTR(new List(b, PTR(new List(NULL,NULL)) )) ))
I was experimenting with C++11 variadac macros.
I was trying to apply another macro to each argument in the list.
This is my first try:
#define APPLY_CHAIN(first, ...) APPLY_ACT(first) APPLY_CHAIN( __VA_ARGS__ )
Unfortunately this did not work.
I eventually got it to work. But it was a bit convoluted and has a limit of 'n' (where 'n' is a max size that I am willing to type macros for).
#define COUNT_N(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N
#define COUNT(...) COUNT_N( __VA_ARGS__, 10, 9, 8, 7, 6, 5 ,4, 3, 2, 1)
#define BUILD_CHAIN_1(_1) APPLY_ACT(_1)
#define BUILD_CHAIN_2(_1, ...) APPLY_ACT(_1) BUILD_CHAIN_1(__VA_ARGS__)
#define BUILD_CHAIN_3(_1, ...) APPLY_ACT(_1) BUILD_CHAIN_2(__VA_ARGS__)
#define BUILD_CHAIN_4(_1, ...) APPLY_ACT(_1) BUILD_CHAIN_3(__VA_ARGS__)
#define BUILD_CHAIN_5(_1, ...) APPLY_ACT(_1) BUILD_CHAIN_4(__VA_ARGS__)
#define BUILD_CHAIN_6(_1, ...) APPLY_ACT(_1) BUILD_CHAIN_5(__VA_ARGS__)
#define BUILD_CHAIN_7(_1, ...) APPLY_ACT(_1) BUILD_CHAIN_6(__VA_ARGS__)
#define BUILD_CHAIN_8(_1, ...) APPLY_ACT(_1) BUILD_CHAIN_7(__VA_ARGS__)
#define BUILD_CHAIN_9(_1, ...) APPLY_ACT(_1) BUILD_CHAIN_8(__VA_ARGS__)
#define BUILD_CHAIN_10(_1,...) APPLY_ACT(_1) BUILD_CHAIN_9(__VA_ARGS__)
#define BUILD_CHAIN_INC( CT, ...) BUILD_CHAIN_ ## CT (__VA_ARGS__)
#define BUILD_CHAIN( CT, ...) BUILD_CHAIN_INC(CT, __VA_ARGS__)
#define APPLY_CHAIN(...) BUILD_CHAIN( COUNT(__VA_ARGS__), __VA_ARGS__)
#define APPLY_ACT(X) #X
#include <iostream>
int main()
{
std::cout << APPLY_CHAIN(1,2,3,4,5) << "\n";
}
So my question is: Am I missing something simple that would allow me iterate along the argument chain?
Your solution to the argument count problem is the same as the one posted to [comp.lang.c] (IIRC) by Laurent Deniau in January 2006.
Modified to work also with Visual C++, his argument counting looks like this:
#pragma once
/*
* The PP_NARG macro evaluates to the number of arguments that have been
* passed to it.
*
* Laurent Deniau, "__VA_NARG__," 17 January 2006, <comp.std.c> (29 November 2007).
* https://groups.google.com/forum/?fromgroups=#!topic/comp.std.c/d-6Mj5Lko_s
*/
// Added workaround for silly MSVC bug that yields "too few parameters" warning.
// - Alf
#include <progrock/cppx/macro/invoke.h> // CPPX_INVOKE
#include <progrock/cppx/macro/concat.h> // CPPX_CONCAT
#define PP_ARG_N( \
_1, _2, _3, _4, _5, _6, _7, _8, _9,_10, \
_11,_12,_13,_14,_15,_16,_17,_18,_19,_20, \
_21,_22,_23,_24,_25,_26,_27,_28,_29,_30, \
_31,_32,_33,_34,_35,_36,_37,_38,_39,_40, \
_41,_42,_43,_44,_45,_46,_47,_48,_49,_50, \
_51,_52,_53,_54,_55,_56,_57,_58,_59,_60, \
_61,_62,_63,N,...) N
#define PP_RSEQ_N() \
63,62,61,60, \
59,58,57,56,55,54,53,52,51,50, \
49,48,47,46,45,44,43,42,41,40, \
39,38,37,36,35,34,33,32,31,30, \
29,28,27,26,25,24,23,22,21,20, \
19,18,17,16,15,14,13,12,11,10, \
9,8,7,6,5,4,3,2,1,0
#if 0
#define PP_NARG_(...) PP_ARG_N( __VA_ARGS__ )
#define PP_NARG( ...) PP_NARG_( __VA_ARGS__, PP_RSEQ_N() )
#else
#define PP_NARG_(...) CPPX_INVOKE( PP_ARG_N, (__VA_ARGS__) )
#define PP_NARG(...) PP_NARG_(__VA_ARGS__,PP_RSEQ_N())
#endif
The CPPX_CONCAT macro:
#pragma once
#define CPPX_CONCAT__( a, b ) a ## b
#define CPPX_CONCAT_( a, b ) CPPX_CONCAT__( a, b )
#define CPPX_CONCAT( a, b ) CPPX_CONCAT_( a, b )
The CPPX_INVOKE macro:
#pragma once
#define CPPX_INVOKE( macro, args ) macro args
Example usage:
#pragma once
#include <progrock/cppx/macro/nargs.h> // CPPX_NARGS, CPPX_CONCAT
#define CPPX_IS_UNUSED_( name ) \
(void) name; struct name
#define CPPX_IS_UNUSED_1( a ) \
CPPX_IS_UNUSED_( a )
#define CPPX_IS_UNUSED_2( a, b ) \
CPPX_IS_UNUSED_1( a ); CPPX_IS_UNUSED_( b )
#define CPPX_IS_UNUSED_3( a, b, c ) \
CPPX_IS_UNUSED_2( a, b ); CPPX_IS_UNUSED_( c )
#define CPPX_IS_UNUSED_4( a, b, c, d ) \
CPPX_IS_UNUSED_3( a, b, c ); CPPX_IS_UNUSED_( d )
#define CPPX_IS_UNUSED_5( a, b, c, d, e ) \
CPPX_IS_UNUSED_4( a, b, c, d ); CPPX_IS_UNUSED_( e )
#define CPPX_IS_UNUSED( ... ) \
CPPX_INVOKE( CPPX_CONCAT( CPPX_IS_UNUSED_, CPPX_NARGS( __VA_ARGS__ ) ), ( __VA_ARGS__ ) )
#define CPPX_IS_INTENTIONALLY_UNUSED CPPX_IS_UNUSED
As this exemplifies the main clue is to not use recursion (at least not directly), but instead manual code repetition for each number of arguments.
I believe that recursive macros are not formally possible. However, few compilers are conforming in this area, and some years ago at least you could indeed cajole WIndows compilers into doing recursive macro substitution. As I recall that was the technique originally used in the code that eventually became the Boost Preprocessor Library (now it uses formally valid code, by centralizing a big list of number-of-arguments-specific handlers, except workarounds for compiler-specific quirks).
That code repetition can most probably be automated via the Boost Preprocessor library, but then you'd use Boost also for the other stuff (presumably the point is to avoid dependency on a large library like Boost, at least that was my motivation when I wrote the above).
Disclaimer: I didn't retry this code before posting and I can't remember whether it was in a state of being modified, or what. But it does show the general principles.
It would appear that recursive macros are still not possible, since the preprocessor only takes one pass over the source.
I bet you could make an explicit looping construct using a dummy #include using a conditional guard (which is perhaps what boost.preprocessor ends up doing.)
Look at Boost.Preprocessor. Specifically BOOST_PP_SEQ_FOLD_LEFT. You'll need BOOST_PP_VARIADIC_TO_SEQ.
Something like
#include <boost/preprocessor.hpp>
#include <iostream>
#define OP(d, state, x) state BOOST_PP_STRINGIZE(x)
#define APPLY_CHAIN(...) BOOST_PP_SEQ_FOLD_LEFT( OP, BOOST_PP_EMPTY() , BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__) )
int main() {
std::cout << APPLY_CHAIN(1,2,3,4,5) << std::endl;
}
//expands to std::cout << "1" "2" "3" "4" "5" << std::endl;
This question is a follow-on from https://stackoverflow.com/a/5365786/383306.
#define _DEFINE_REF_INTERNAL2(id, ...)
#define _DEFINE_REF_INTERNAL1(id)
#define _VA_NARGS_2_IMPL(_1, _2, N, ...) N
#define _VA_NARGS_2(...) _VA_NARGS_2_IMPL(__VA_ARGS__, 2, 1)
#define _DEFINE_REF_IMPL2(count, ...) _DEFINE_REF_INTERNAL ## count (__VA_ARGS__)
#define _DEFINE_REF_IMPL(count, ...) _DEFINE_REF_IMPL2(count, __VA_ARGS__)
#define DEFINE_REF(...) _DEFINE_REF_IMPL(_VA_NARGS_2(__VA_ARGS__), __VA_ARGS__)
DEFINE_REF(MyClass, typename... Args, Args...);
// error: ‘_DEFINE_REF_INTERNALArgs’ does not name a type
DEFINE_REF(MyClass, typename T, T); // this is OK
How do I make the macro trick work when passing ellipsis as part of an argument?
The problem isn't with the ellipsis. The problem is that you are passing three arguments in __VA_ARGS__ to DEFINE_REF, but _VA_NARGS_2 only handles up to two arguments.
Once you fix that, the program (I believe) exhibits the desired behavior. gcc 4.7.2 and Clang 3.2 both transform this:
#define DEFINE_REF_INTERNAL3(arg0, arg1, arg2) [arg0] [arg1] [arg2]
#define VA_NARGS_(_1, _2, _3, N, ...) N
#define VA_NARGS(...) VA_NARGS_(__VA_ARGS__, 3, 2, 1)
#define DEFINE_REF_IMPL_(count, ...) DEFINE_REF_INTERNAL ## count(__VA_ARGS__)
#define DEFINE_REF_IMPL(count, ...) DEFINE_REF_IMPL_(count, __VA_ARGS__)
#define DEFINE_REF(...) DEFINE_REF_IMPL(VA_NARGS(__VA_ARGS__), __VA_ARGS__)
DEFINE_REF(MyClass, typename... Args, Args...);
DEFINE_REF(MyClass, typename T, T );
into this:
[MyClass] [typename... Args] [Args...];
[MyClass] [typename T] [T];
(Also note that names beginning with an underscore followed by a capital letter are reserved for the implementation. You may not use such names for your own macros.)
If you are targeting Visual C++, you will need a barrel of indirection to make this work, as it does not correctly replace macros before rescanning in all cases. The following will work with Visual C++ (This solution is also conforming and works with gcc and Clang as well):
#define DEFINE_REF_INTERNAL3(id, arg0, arg1) id [arg0] [arg1]
#define CONCATENATE_(x, y) x ## y
#define CONCATENATE(x, y) CONCATENATE_(x, y)
#define VA_NARGS1(_1, _2, _3, N, ...) N
#define VA_NARGS0(x) VA_NARGS1 x
#define VA_NARGS(...) VA_NARGS0((__VA_ARGS__, 3, 2, 1))
#define DEFINE_REF_IMPL1(macro, pargs) macro pargs
#define DEFINE_REF_IMPL0(count, ...) \
DEFINE_REF_IMPL1(CONCATENATE(DEFINE_REF_INTERNAL, count), (__VA_ARGS__))
#define DEFINE_REF_IMPL(count, ...) DEFINE_REF_IMPL0(count, __VA_ARGS__)
#define DEFINE_REF(...) DEFINE_REF_IMPL(VA_NARGS(__VA_ARGS__), __VA_ARGS__)