# Boost Users :

From: Tobias Schwinger (tschwinger_at_[hidden])
Date: 2007-06-19 06:06:03

Server Levent Yilmaz wrote:
> Take a look at this:
>
> #define SPECIAL
> #define IS_SPECIAL(x) BOOST_PP_IS_EMPTY(BOOST_PP_EMPTY() x)
>
> #define MACRO(i,z,array) IS_SPECIAL( BOOST_PP_ARRAY_ELEM(i, array) )
> #define ENUM( n, tuple ) BOOST_PP_ENUM( n, MACRO, (n, tuple) )
>
> ENUM( 3, ( arg1, , arg3) ) //1
> ENUM( 3, ( arg1, SPECIAL, arg3) ) //2
>
>
> In this context, can we safely say that 2 complies with standards more
> than 1?

No, because the argument to IS_SPECIAL (within MACRO) might expand to
emptiness, anyway.

#define MACRO(z,i,array) BOOST_PP_IS_EMPTY(BOOST_PP_EMPTY() \
BOOST_PP_ARRAY_ELEM(i,array) )

Is better, though still not correct: SPECIAL within 'array' expands to
nothing before 'array' is passed to PP_ARRAY_ELEM. Now the problem
occurs within the PP library.

Now we'd have to know the exact number of expansions to defer the
expansion of SPECIAL so many times that the final expansion to emptiness
happens just within PP_IS_EMPTY:

#define E() // Empty
#define X(x) x // eXpand

// demonstrate expansion gets deferred

E E E E()()()() // E E E ()()()

X( E E E E()()()() ) // E E ()

X(X( E E E E()()()() )) // E ()

X(X(X( E E E E()()()() ))) //

#define SPECIAL E E E E E E E E E E E E E E E E E E E E E \
()()()()()()()()()()()()()()()()()()()()()

//#define MACRO(z,i,array) \
// BOOST_PP_IS_EMPTY( BOOST_PP_ARRAY_ELEM(i, array) )
#define MACRO(z,i,array) BOOST_PP_ARRAY_ELEM(i, array)

#define ENUM( n, tuple ) BOOST_PP_ENUM( n, MACRO, (n, tuple) )

ENUM(3, (arg1, SPECIAL, arg3)) // arg1 , E () , arg3

This code works as expected with the GNU preprocessor. You can't rely on
the number of expansions to be the same for another PP, since Boost.PP
might have to correct PP misbehavior, taking a different "control path",
for things to work at all.

It's quite easy to cross the line messing with emptiness

#define FOO(x) _ ## x
#define BAR(x) FOO(x)

FOO(BOOST_PP_EMPTY()) // OK, expands to _BOOST_PP_EMPTY()
BAR(BOOST_PP_EMPTY()) // -undefined behavior-

so ideally one finds a way not to have to mess with it at all, e.g:

#define SAFE(optional) optional()
#define STILL_SAFE(optional) SAFE(optional)

SAFE(BOOST_PP_EMPTY) // expands to nothing
SAFE(BOOST_PP_IDENTITY(xyz)) // xyz
STILL_SAFE(BOOST_PP_EMPTY) // expands to nothing

Regards,
Tobias