Boost logo

Boost :

Subject: Re: [boost] painless currying
From: Paul Mensonides (pmenso57_at_[hidden])
Date: 2011-09-01 00:07:18


On Wed, 31 Aug 2011 16:09:30 -0400, Edward Diener wrote:

> instead. Although this change still produces compiler errors with gcc
> and Boost 1.47 and below ( Paul Mensonsides is looking into that since
> he knows how iteration works with Boost PP ), it solves the problem
> compiling with gcc and the latest Boost PP on the trunk.

Okay, here's what's going on...

1) GCC performs macro expansion and parsing on the expressions of all #if/
#elif/#endif blocks that it encounters when not already skipping because
of an outer #if/#endif. It is questionable whether this is what was
intended, but it is arguable either way. Thus, code like this

#if !BOOST_PP_IS_ITERATING

  // ...

#elif BOOST_PP_ITERATION_FLAGS() == 1

  // ...

#elif BOOST_PP_ITERATION_FLAGS() == 2

  // ...

#endif

should be altered to

#if !BOOST_PP_IS_ITERATING

#else

    #if BOOST_PP_ITERATION_FLAGS() == 1

        // ...

    #else

        // ...

    #endif

#endif

The second problem is that the iteration flags are not "evaluated" in the
way that the iteration bounds are evaluated but are instead defined to be
the whatever was put in the iteration parameters. The error occurs in
the during the nested iteration (that includes the SUB, etc.). The
ultimate problem is in the way that BOOST_PP_ITERATION_FLAGS() is defined
in the <= 1.47 codebase which is essentially:

CAT(ITERATION_FLAGS_, ITERATION_DEPTH())

This concatenation forms ITERATION_FLAGS_2, in this case, which, in turn
tries to extract the flags via ARRAY_ELEM(3, ITERATION_PARAMS_2). The
ITERATION_PARAMS_2 value, however, uses SUB, which uses one of the
parentheses detection macros to check for zero. However, those detection
macros require CAT--which doesn't expand because we're already "inside"
CAT--which prevents the intermediate from expanding from a single
"argument" to two "arguments", and then you get the diagnostic.

The fix, which has already been in the trunk for a while is to alter the
headers as follows:

boost/preprocessor/iteration/iterate.hpp
- alter the definition of ITERATION_FLAGS() from
  (BOOST_PP_CAT(BOOST_PP_ITERATION_FLAGS_, BOOST_PP_ITERATION_DEPTH()))
  to
  (BOOST_PP_CAT(BOOST_PP_ITERATION_FLAGS_, BOOST_PP_ITERATION_DEPTH())())

(i.e. changing ITERATION_FLAGS_n into a function-like macro)

boost/preprocessor/iteration/detail/iter/forward1.hpp
                                         ... 2.hpp
                                         ... 3.hpp
                                         ... 4.hpp
                                         ... 5.hpp

- each of these five headers contain definitions of ITERATION_FLAGS_n in
three places near the top. These all need to be changed to nullary
function-like macros instead of object-like macros.

That will fix the problem.

Alternatively, the iteration flags are "supposed" to be used to
distinguish between different iterations at the same depth. Here,
however, they are being used where they don't need to be. The iteration
flags could have been elided and just use ITERATION_DEPTH() instead...

#if !IS_ITERATING

#else

  #if ITERATION_DEPTH() == 1

  #elif ITERATION_DEPTH() == 2

  #endif

#endif


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