Boost logo

Boost :

From: Paul Mensonides (pmenso57_at_[hidden])
Date: 2005-02-12 20:10:16


> -----Original Message-----
> From: boost-bounces_at_[hidden]
> [mailto:boost-bounces_at_[hidden]] On Behalf Of Arkadiy Vertleyb

> Hi Paul,
>
> > Is there any particular reason why you need 'i' in the
> outer dimension?
> If not,
> > regular SEQ_FOR_EACH and SEQ_FOR_EACH_I should work together:
>
> Actually yes, I do need it -- I am generating series of
> typedefs, each one depending on the previous, and I need to
> generate names for them. I also need 'i' in the inner loop.

Okay.

> My guess is, I have to use REPEAT, passing sequence as
> auxiliary data, and using SEQ_ELEM to access current element.
> This looks a little clumsier, and probably less efficient
> (?) than more native SEQ_FOR_EACH, but it's fine with me as
> long as I know that this is the best I can do in this case
> (REPEAT *is* reentrant, right?).

There are a variety of ways that you could do it. The first way that I thought
of would be to transform the outer sequence with SEQ_FOR_EACH_I and then process
the result with SEQ_FOR_EACH_I...

#include <boost/preprocessor/seq/for_each.hpp>
#include <boost/preprocessor/seq/for_each_i.hpp>
#include <boost/preprocessor/tuple/elem.hpp>

#define A(r, _, i, elem) ((i, elem))
#define B(r, _, pair) \
    BOOST_PP_SEQ_FOR_EACH_I( \
        C, \
        BOOST_PP_TUPLE_ELEM(2, 0, pair), \
        BOOST_PP_TUPLE_ELEM(2, 1, pair) \
    ) \
    /**/
#define C(r, i, j, elem) elem(i, j)

BOOST_PP_SEQ_FOR_EACH(
    B, ~,
    BOOST_PP_SEQ_FOR_EACH_I(
        A, ~,
        ((a)(b)(c))
        ((d)(e)(f))
        ((g)(h)(i))
    )
)

--> a(0, 0) b(0, 1) c(0, 2) d(1, 0) e(1, 1) f(1, 2) g(2, 0) h(2, 1) i(2, 2)

That is probably what I'd do, and is probably more efficient than REPEAT
w/SEQ_ELEM.

To answer you're other question, yes, REPEAT is reentrant.

> Also, do I understand correctly, that, if I wanted to wrap
> the call to REPEAT in yet another macro, something like
> SEQ_ENUM[_TRAILING](seq, macro), I would have to take care
> myself of this macro to be reentrant? In the simplest case,
> I would just have to provide two identical macros, SEQ_ENUM_0
> and SEQ_ENUM_1, and use the first one outside, and the second
> -- inside (this would take care of one layer nesting).

Basically, yes. This is pretty much what the library has to do as well for
anything reentrant (but with far more replications).

I've been thinking about various ways to generalize some of this that I might be
able to get away with in the pp-lib (read: ...that I might be able to implement
even on typical preprocessors...). However, that might imply always doing
everything automatically--meaning with automatic recursion on everything and no
syntax for direct reentrance (i.e. no z, r, d, etc., state variables). Even if
I take away the compiler workarounds in the pp-lib, and even if I don't use any
of the "fancy" things that Chaos does, there are still some fundamental problems
with the pp-lib (IMO). In particular, I don't like this exact situation where
reuse of algorithms to create other algorithms creates a dependency and removing
the dependency requires removing the reuse. I also don't like there being
multiple states (such as z, r, and d). The main idea is to distinguish between
entry point and algorithmic step. As an example, WHILE needs to be able to make
many algorithmic steps, but it doesn't really need all that many entry points
(i.e. is unlikely that a user would need more than, say, two or three nested
invocations of WHILE). Given that, it is possible to map a small set of entry
points onto a larger set of algorithmic steps. The questions are whether it is
possible to implement this on buggy preprocessors (which I think it is) and
whether it is worth it because it is still less than ideal.

> > (Of course, this design limitation doesn't exist in Chaos. All
> higher-order
> > macros are reentrant--without implementation replication.)
>
> But I would still have to take special care of reentrancy of
> my own macros, correct?

Yes, but it isn't terribly difficult. There is a difference also between
recursion and arbitrary reentrancy. I.e. designing a recursive algorithm with
Chaos is fairly easy, designing a higher-order recursive algorithm is slightly
more difficult, but still fairly easy. Neither involve macro replication.

> I actually think disallowing
> recursion of function-like macros is totally artificial and
> unjustified in the first place :-(

I agree. Not only that, but it is also the single greatest cause of
inefficiency in complex macro expansion. OTOH, the lack of recursion allows
some meaningful things that could not be done any other way (assuming the
preprocessor is otherwise the same).

Regards,
Paul Mensonides


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk