Boost logo

Boost Users :

From: Tobias Schwinger (tschwinger_at_[hidden])
Date: 2006-03-11 17:38:29


Marc Mutz wrote:
> Hi,
>
> I'm having a problem with "free" commas in macro expansions. I want to
> generate some function declarations (and implementations) from a
> user-supplied BOOST_PP_SEQ. The function declarations use enable_if to switch
> between two sets of interfaces based on the type that shall be returned.
> Nevermind the details, I've just used a trivial enabling condition here, the
> error is the same as when using mpl::contains<sometype, Type> in the real
> code. I've stripped the problem down and attached a test file, complete with
> my documented attempts to delay expansion of the comma somehow. The
> preprocessor succeeds when the enable_if or it's two template args are put
> into (parentheses), but this is no longer valid C++, of course.
>
> I guess I'm missing something, but I'm at the end of my Latin, as we say in
> Germany.
>

OK, then let's make it the egg's yellow ;-).

The IF should be lazy (otherwise it won't do what you want, because IF evaluates SEQ_FOR_EACH no matter what the condition is). In code this means:

    #define OSD_SEQ_FOR_EACH_BUT_LAST( macro, data, seq ) \
        BOOST_PP_IIF( BOOST_PP_GREATER( BOOST_PP_SEQ_SIZE( seq ), 1 ), \
                     BOOST_PP_SEQ_FOR_EACH, BOOST_PP_TUPLE_EAT(3)) \
        ( macro, data, BOOST_PP_SEQ_POP_BACK( seq ) )

Now IF only expands to the name of SEQ_FOR_EACH (without arguments) and the invocation happens outside of the IF (in the else-case TUPLE_EAT is used to just consume the arguments) so TRY=1 just works without feeding too much arguments to IF-internals.

Also note that I use 'IIF' instead of 'IF'. 'IF' maps values >1 to 1 (bool-conversion) which is not needed here because the result of GREATER is either 0 or 1.

 
Further, you shouldn't use empty arguments (like the else-argument to IF in your code) and '()' as your end-marker: It's not entirely C++, because according to the current standard empty macro arguments result in undefined behaviour (althoug preprocessor except them in most cases).

The usual way around the empty arguments issue is again lazy evaluation -- this time with EMPTY or IDENTITY, where 'EMPTY()' expands to nothing and 'IDENTITY(whatever)()' expands to 'whatever'.

Although your particular problem seems solved already here is some bonus: It /is/ possible to pass a parenthesized type expression (with any number of commas) to a macro and use it as a type expression on the C++ side again by building and decomposing a function pointer. See the RP_TYPE macro, defined at the very bottom of http://tinyurl.com/qnmfz for details.

Regards,

Tobias


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net