Search code examples
c++boostboost-preprocessor

Boost preprocessor not expanding


I have the following code:

#include <boost/preprocessor.hpp>

#define ARGS(r, data, elem) \
    BOOST_PP_COMMA_IF(BOOST_PP_SUB(r, 2)) \
    BOOST_PP_SEQ_ELEM(0, elem) BOOST_PP_SEQ_ELEM(1, elem)

#define DEF_FUN(name, args) void name(BOOST_PP_SEQ_FOR_EACH(ARGS,,args));

#define DEF_FUNCTIONS_ELEM(r, data, elem) DEF_FUN(BOOST_PP_SEQ_ELEM(0, elem), BOOST_PP_SEQ_ELEM(1, elem))

#define DEF_FUNCTIONS(funSeqs) \
    BOOST_PP_SEQ_FOR_EACH(DEF_FUNCTIONS_ELEM,, funSeqs)


DEF_FUNCTIONS_ELEM(2,, (fun0) (((int)(arg0))   ((char)(arg1))))

DEF_FUNCTIONS
(
    ((fun0) (((int)(arg0))   ((char)(arg1))))
    ((fun1) (((char)(arg0))  ((long)(arg1)) ((short)(arg2))))
    ((fun3) ())
)

When I preprocess this with Clang 3.2 or g++ 4.6.3, I get:

void fun0( int arg0 , char arg1 );

void fun0(BOOST_PP_SEQ_FOR_EACH(ARGS,,((int)(arg0)) ((char)(arg1)))); 
void fun1(BOOST_PP_SEQ_FOR_EACH(ARGS,,((char)(arg0)) ((long)(arg1)) ((short)(arg2)))); 
void fun3(BOOST_PP_SEQ_FOR_EACH(ARGS,,)); 

(I added line-breaks for clarity)

The question is, why is the inner BOOST_PP_SEQ_FOR_EACH not expanded?

Passing this output again expands the expected result.

EDIT: After a lot of searching I read that a macro wont expand if it's called twice, I think that's why.

EDIT: I should've used PP_SEQ_FOR_EACH_I, the R is not meant to be used as a subscript.


Solution

  • BOOST_PP_SEQ_FOR_EACH is not reentrant. There are only a few macros in Boost.PP that are reentrant(BOOST_PP_FOR, BOOST_PP_WHILE, and BOOST_PP_REPEAT). However, you can workaround it by using deferred expressions, like this:

    #include <boost/preprocessor.hpp>
    
    #define EXPAND(...) __VA_ARGS__
    #define EMPTY()
    #define DEFER(x) x EMPTY()
    // An indirection macro to avoid direct recursion
    #define BOOST_PP_SEQ_FOR_EACH_ID() BOOST_PP_SEQ_FOR_EACH
    
    #define ARGS(r, data, elem) \
        BOOST_PP_COMMA_IF(BOOST_PP_SUB(r, 2)) \
        BOOST_PP_SEQ_ELEM(0, elem) BOOST_PP_SEQ_ELEM(1, elem)
    
    // Defer BOOST_PP_SEQ_FOR_EACH_ID here
    #define DEF_FUN(name, args) void name(DEFER(BOOST_PP_SEQ_FOR_EACH_ID)()(ARGS,,args));
    
    #define DEF_FUNCTIONS_ELEM(r, data, elem) DEF_FUN(BOOST_PP_SEQ_ELEM(0, elem), BOOST_PP_SEQ_ELEM(1, elem))
    
    // Add EXPAND here to apply another scan to expand the deferred expression
    #define DEF_FUNCTIONS(funSeqs) \
        EXPAND(BOOST_PP_SEQ_FOR_EACH(DEF_FUNCTIONS_ELEM,, funSeqs))
    
    
    DEF_FUNCTIONS
    (
        ((fun0) (((int)(arg0))   ((char)(arg1))))
        ((fun1) (((char)(arg0))  ((long)(arg1)) ((short)(arg2))))
        ((fun3) ())
    )