|
Boost : |
Subject: Re: [boost] [preprocessor] nested for_each not working like expected
From: paul Fultz (pfultz2_at_[hidden])
Date: 2013-08-10 14:53:25
> I won't pretend to understand how this works, but it does. Thanks!
Your weclome. Here's how it works. First, it uses a deferred expression, which
requires one more scan to fully expand like this:
#define EMPTY()
#define DEFER(x) x EMPTY()
#define EXPAND(...) __VA_ARGS__
#define A() 123
A() // Expands to 123
DEFER(A)() // Expands to A () because it requires one more scan to fully expand
EXPAND(DEFER(A)()) // Expands to 123, because the EXPAND macro forces another scan
This will help dance around getting our macros from being painted blue(which
won't expand any further, no matter what). When the preprocessor scans and
then expands a macro, it first creates a disabling context. A disabling
context is basically a list of tokens, that if the preprocessor see them
during the scan it will paint them blue. So in this case, when it expands
`BOOST_PP_SEQ_FOR_EACH_R(1, M2, ~, S0)` it will add `BOOST_PP_SEQ_FOR_EACH_R`
to the disabling context. So then it scans and expands like this:
BOOST_PP_SEQ_FOR_EACH_R_ID ()(1, M4, 0, (5)(6)(7)(8)); BOOST_PP_SEQ_FOR_EACH_R_ID ()(1, M4, 1, (5)(6)(7)(8)); BOOST_PP_SEQ_FOR_EACH_R_ID ()(1, M4, 2, (5)(6)(7)(8)); BOOST_PP_SEQ_FOR_EACH_R_ID ()(1, M4, 3, (5)(6)(7)(8));
After its done, `BOOST_PP_SEQ_FOR_EACH_R` is removed from the disabling
context. All we need to do is apply one more scan to expand each of the
`BOOST_PP_SEQ_FOR_EACH_R_ID` macros. We can use `BOOST_PP_EXPAND` to do this,
but when it expands, `BOOST_PP_SEQ_FOR_EACH_R` is not in the disabling
context, so it will fully expand. Hopefully, that makes sense. Perhaps, Paul
Mensonides, can explain it better than I can.
> Why not just use BOOST_PP_REPEAT otherwise? It's simple and it always works.
Using deferred expression is a more general purpose solution. Eric never gave
any details to what he was doing. Perhaps, he was already using
`BOOST_PP_REPEAT`. Also, to use effeciently requires passing along another
recursion state. Plus, using deferred expressions scales further, if 3
`BOOST_PP_SEQ_FOR_EACH` macros are needed, it can be extended easily.
> Isn't accessing the Nth element of a PP sequence O(N)? Seems to me that
> what Paul posted would be more efficient.
Actually accessing the elements are near random access, because it uses
sequence iteration, which is super fast(Still not necessarily faster than
using nested `BOOST_PP_SEQ_FOR_EACH` macros, although I haven't taken the time
to measure it). If you don't need a data parameter, its much faster using
sequence iteration, than `BOOST_PP_SEQ_FOR_EACH`, something like this:
#define PRINT(x) x
#define PRINT_SEQ(x) BOOST_PP_CAT(PRINT_SEQ_1 x, _END)
#define PRINT_SEQ_1(x) PRINT(x) PRINT_SEQ_2
#define PRINT_SEQ_2(x) PRINT(x) PRINT_SEQ_1
#define PRINT_SEQ_1_END
#define PRINT_SEQ_2_END
PRINT_SEQ((1)(2)(3)) // Expands to 1 2 3
Paul Fultz II
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk