Can't understand how the BOOST_PP_REPEAT_FROM_TO example works]

Hi everyone, I'm new to boost but I did search the group as thoroughly as I could before asking this. Anyway, the documentation gives this as an example: #include <boost/preprocessor/cat.hpp> #include <boost/preprocessor/repetition/repeat_from_to.hpp> #define DECL(z, n, text) BOOST_PP_CAT(text, n) = n; BOOST_PP_REPEAT_FROM_TO(5, 10, DECL, int x) /* expands to: int x5 = 5; int x6 = 6; int x7 = 7; int x8 = 8; int x9 = 9; */ What confuses me is that BOOST_PP_REPEAT_FROM_TO expands to BOOST_PP_CAT and so does DECL yet after expanding DECL to BOOST_PP_CAT the (comeau) preprocessor continues to expand BOOST_PP_CAT to give the desired result. However, in the following code: #define CONCAT_1(a, b) CONCAT_1_D(a, b) #define CONCAT_1_D(a, b) a ## b #define CONCAT_2(a, b) CONCAT_2_D(a, b) #define CONCAT_2_D(a, b) a ## b #define AB(c, x, y) CONCAT_ ## c(x,y) CONCAT_1(A, B(1, p, q)) we find that we get: CONCAT_1(p,q) Only by changing the code to: CONCAT_1(A, B(2, p, q)) // note the 2 rather than 1 do we get our desired result: pq Can someone explain what I'm not understanding here (this isn't in my usual field of work)? Many thanks in anticipation Brad

-----Original Message----- From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org] On Behalf Of Bradley Smith
I'm new to boost but I did search the group as thoroughly as I could before asking this. Anyway, the documentation gives this as an example:
I don't have time to answer this until I get off of work (about nine hours from now). In the mean time, take a look at the "reentrancy" topic in the documentation. It might help. Regards, Paul Mensonides

-----Original Message----- From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org] On Behalf Of Bradley Smith
Hi Brad. Okay, a little more time now...
I'm new to boost but I did search the group as thoroughly as I could before asking this. Anyway, the documentation gives this as an example:
#include <boost/preprocessor/cat.hpp> #include <boost/preprocessor/repetition/repeat_from_to.hpp>
#define DECL(z, n, text) BOOST_PP_CAT(text, n) = n;
BOOST_PP_REPEAT_FROM_TO(5, 10, DECL, int x) /* expands to: int x5 = 5; int x6 = 6; int x7 = 7; int x8 = 8; int x9 = 9; */
What confuses me is that BOOST_PP_REPEAT_FROM_TO expands to BOOST_PP_CAT and so does DECL yet after expanding DECL to BOOST_PP_CAT the (comeau) preprocessor continues to expand BOOST_PP_CAT to give the desired result.
#define A() B #define B() ... A()() The difference between the documentation example an your example below boils down to the above situation. The invocation of 'B' is not geographically nested in 'A', and therefore the context that disables 'A' is no longer active when 'B' is expanded. REPEAT_FROM_TO works in roughly the same way. The macro itself is an object-like macro that expands to a different macro name, similar to what 'A' does above, except that it is deducing which of several macros should be used (it is detecting the presence or lack of disabling contexts). For example, say that you have... #define REPEAT_FROM_TO_1(a, b, macro, data) // ... #define REPEAT_FROM_TO_2(a, b, macro, data) // ... #define REPEAT_FROM_TO_3(a, b, macro, data) // ... IOW, three (in this example) distinct copies of the REPEAT_FROM_TO implementation. Now, say that you use one of them: #define MACRO(z, n, data) // ... REPEAT_FROM_TO_1(1, 5, MACRO, ~) Now, when 'MACRO' gets invoked by REPEAT_FROM_TO_1, the disabling context on REPEAT_FROM_TO_1 is still active, and thus REPEAT_FROM_TO_1 cannot be used by 'MACRO'--so it must use REPEAT_FROM_TO_2 instead. The library can detect whether or not the disabling context on (e.g.) REPEAT_FROM_TO_1 is active (similarly with REPEAT_FROM_TO_2, etc.). So, what it does is define an interface macro that redirects to one of these three implementations. This interface is really an object-like macro, though a use of it looks like an invocation of a function-like macro: #define REPEAT_FROM_TO [choose to 'return' REPEAT_FROM_TO_1, _2, or _3] REPEAT_FROM_TO (1, 5, MACRO, ~) |______________| This first part expands by itself (the argument list is irrelevant to it) to REPEAT_FROM_TO_1, _2, or _3. Whichever macro name it "returns" expands against the argument list, and you have the same situation as the 'A' 'B' example above. The invocation of (e.g.) REPEAT_FROM_TO_1 against the argument list is not nested in either REPEAT_FROM_TO or any of the macros that it uses to derive its result.
However, in the following code:
#define CONCAT_1(a, b) CONCAT_1_D(a, b) #define CONCAT_1_D(a, b) a ## b #define CONCAT_2(a, b) CONCAT_2_D(a, b) #define CONCAT_2_D(a, b) a ## b #define AB(c, x, y) CONCAT_ ## c(x,y)
This example, OTOH, is like #define A() B() #define B() ... ...rather than like the 'A' 'B' example above. Here, the invocation of 'B' is geographically nested in the replacement list of 'A'. Thus, when 'B' is expanded, the disabling context of 'A' is still active and any further uses of 'A' won't expand.
Can someone explain what I'm not understanding here (this isn't in my usual field of work)?
Does that help? Regards, Paul Mensonides
participants (2)
-
Bradley Smith
-
Paul Mensonides