Boost logo

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