Boost logo

Boost :

From: Paul Mensonides (pmenso57_at_[hidden])
Date: 2005-02-03 05:58:12


 

> -----Original Message-----
> From: boost-bounces_at_[hidden]
> [mailto:boost-bounces_at_[hidden]] On Behalf Of John Eddy
> Sent: Wednesday, February 02, 2005 12:35 PM
> To: boost_at_[hidden]
> Subject: [boost] BOOST_PP_EXPR_IF Behavior
>
> I am not terribly familiar with the rules of the
> preprocessor. Is it the case that the expression of the
> BOOST_PP_EXPR_IF macro is expanded regardless of the
> resulting value of the condition?

For EXPR_IF, yes. If and only if an argument to a macro appears in the
replacement list of that macro without being an operand of # or ##, then that
argument should be expanded on input to the macro--regardless of whether the
argument is relevant to the final result of macro expansion. Note the "and only
if" part above in particular. Minus all the workarounds, EXPR_IF is defined
like this:

#define EXPR_IF(cond, expr) EXPR_IIF(BOOL(cond), expr)

I.e. it simply defers to EXPR_IIF after converting the condition to 0 or 1.
Note that 'expr' appears in the replacement list without being an operand of #
or ##. EXPR_IIF is the same way, but defined differently:

#define EXPR_IIF(bit, expr) CAT(EXPR_IIF_, bit)(expr)
#define EXPR_IIF_0(expr)
#define EXPR_IIF_1(expr) expr

In other words, in both cases, 'expr' will be expanded regardless of 'cond' or
'bit'.

With that said, EXPR_IF (etc.) is only defined that the way it is because
preprocessors are non-conformant. If I could encapsulate their problems (which
I can't), I would do it this way:

#define EXPR_IF(cond) CAT(EXPR_IF_, BOOL(cond))
#define EXPR_IF_0(expr)
#define EXPR_IF_1(expr) expr

The usage syntax would then be:

EXPR_IF ( condition ) ( expression )

instead of

EXPR_IF ( condition , expression )

The difference is that the former is lazy. If 'cond' is 0, 'expr' is passed to
a macro that does not mention 'expr' in its replacement list and thus should not
be expanded. Unfortunately, I cannot effectively encapsulate preprocessor bugs
with this kind of "combination" syntax.

[As an aside, to those who may be interested: with placemarkers (i.e. empty
arguments) from C99, macros can propogate "lack of evaluation" by placemarker
concatenation--which does not change the tokens in the argument but does prevent
them from expanding on input.]

> The warning is:
>
> C4003: not enough actual parameters for macro 'BOOST_PP_EXPR_IIF_0'
>
> The macro expands correctly.

Don't rely on that. It's a VC misfeature; it should be an error.

> Perhaps there is a better way to do what I am after. I would
> like to create a comma separated list (no parenthesis as
> would be the case if I only took the array data) from a
> possibly empty set.

Okay, let me see if I understand correctly. You have an array (as in the pp
data structure) which looks like (e.g.):

(0, ())
(1, (a))
(2, (a, b))
(3, (a, b, c))
// etc.

And you want this transformation:

(0, ()) ->
(1, (a)) -> a
(2, (a, b)) -> a, b
(3, (a, b, c)) -> a, b, c

Assuming that that is what you want...

#include <boost/preprocessor/array/data.hpp>
#include <boost/preprocessor/array/size.hpp>
#include <boost/preprocessor/tuple/rem.hpp>

#define ARRAY_ENUM(array) \
    BOOST_PP_TUPLE_REM_CTOR( \
        BOOST_PP_ARRAY_SIZE(array), \
        BOOST_PP_ARRAY_DATA(array) \
    ) \
    /**/

ARRAY_ENUM( (0, ()) ) // ->
ARRAY_ENUM( (1, (a)) ) // -> a
ARRAY_ENUM( (2, (a, b)) ) // -> a, b
ARRAY_ENUM( (3, (a, b, c)) ) // -> a, b, c

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