Search code examples
c++boostnestedc-preprocessorboost-preprocessor

How do I combine BOOST_PP_IF with BOOST_PP_LPAREN?


I'm trying to conditionally expand a macro to either "( a" or "b )", but the naive way of doing so doesn't work on either of the compilers I'm using (Microsoft C/C++ and the NDK compiler). Example:

// This works on both compilers, expands to ( a ) as expected
#define PARENS_AND_SUCH BOOST_PP_IF(1, BOOST_PP_LPAREN() a BOOST_PP_RPAREN(), b)

// MSVC: syntax error/unexpected end of file in macro expansion 
// NDK: unterminated argument list
#define PARENS_AND_SUCH BOOST_PP_IF(1, BOOST_PP_LPAREN() a, b)

// Desired expansion: ( a
// MSVC expansion: ( a, b )
// NDK: error: macro "BOOST_PP_IIF" requires 3 arguments, but only 2 given
#define PARENS_AND_SUCH BOOST_PP_IF(1, BOOST_PP_LPAREN() a, b BOOST_PP_RPAREN())

What am I doing wrong?


Solution

  • You could force the order of evaluation to conform to the expected one by abstracting out the branches of the IF to subdefinitions, and delay their expansion until the conditional returns a branch:

    #define PARENS_AND_SUCH BOOST_PP_CAT(PAS_, BOOST_PP_IF(1, THEN, ELSE))
    #define PAS_THEN BOOST_PP_LPAREN() a
    #define PAS_ELSE b BOOST_PP_RPAREN()
    

    Since THEN and ELSE aren't complete names, the branches will not be expanded before the IF is expanded; when it returns, the value is combined with PAS_ to form a new valid definition and will expand at that time.

    You could also parameterise the THEN and ELSE macros and make this technique more general (and IMO more elegant): passing parameters to an incomplete name essentially forms a thunk, and works pretty much the same way (the incomplete function-like macro name will be passed around plus parameter list until it's completed).