Boost.Preprocessor: expansion stops, result is further expandable

Hello, I'd like to thank everybody involved in creation of Boost.Preprocessor for this cool piece of software, it does wonders. I have a possibly naive question (I'm an autodidact) which involves Boost.PP. I have stumbled upon strange behavior where the preprocessor stops expanding but the output expands further if fed to the preprocessor again. Given these directives: #include <boost/preprocessor.hpp> # #define DAPHP_REGISTER_CLASS(class_, props) \ CXXEXT_REGISTER_CLASS( \ class_ \ , BOOST_PP_SEQ_TRANSFORM(DAPHP_MAKE_PROPERTY, ~, props) \ ) # #define DAPHP_MAKE_PROPERTY(_, __, name) \ (name, IS_LONG, 0) # #define CXXEXT_REGISTER_CLASS(class_, props) \ object< class_ >::register_(); \ CXXEXT_DECLARE_PROPERTIES(class_, props) # #define CXXEXT_DECLARE_PROPERTIES(class_, props) \ BOOST_PP_SEQ_FOR_EACH( \ CXXEXT_DECLARE_PROPERTY_SEQ \ , ~ \ , BOOST_PP_SEQ_TRANSFORM(CXXEXT_PROPERTY_ADD_CLASS, class_, props) \ ) # #define CXXEXT_PROPERTY_ADD_CLASS(_, class_, prop) \ BOOST_PP_ARRAY_DATA(BOOST_PP_ARRAY_PUSH_FRONT((3, prop), class_)) # #define CXXEXT_DECLARE_PROPERTY_SEQ(_, __, elem) \ BOOST_PP_EXPAND(CXXEXT_DECLARE_PROPERTY elem) # #define CXXEXT_DECLARE_PROPERTY(native_type, name, ztype_, default_) \ object< native_type >::declare_property( \ ZEND_ACC_PUBLIC \ , ztype_ \ , BOOST_PP_STRINGIZE(name) \ , default_ \ ); # #define DAPHP_PROPS_DATE (year) (month) (day) This: DAPHP_REGISTER_CLASS(DapiDate, DAPHP_PROPS_DATE) Expands to (newlines added): object< DapiDate >::register_(); object< DapiDate >::declare_property( ZEND_ACC_PUBLIC , IS_LONG , "year" , 0 ); object< DapiDate >::declare_property( ZEND_ACC_PUBLIC , IS_LONG , "month" , 0 ); object< DapiDate >::declare_property( ZEND_ACC_PUBLIC , IS_LONG , "day" , 0 ); With these definitions added to the mix: #define DAPHP_REGISTER_CLASSES(classes) \ BOOST_PP_SEQ_FOR_EACH( \ DAPHP_REGISTER_CLASS_SEQ \ , ~ \ , classes \ ) # #define DAPHP_REGISTER_CLASS_SEQ(_, __, classprops) \ DAPHP_REGISTER_CLASS( \ BOOST_PP_TUPLE_ELEM(2, 0, classprops) \ , BOOST_PP_TUPLE_ELEM(2, 1, classprops) \ ) This: DAPHP_REGISTER_CLASSES( ((DapiDate, DAPHP_PROPS_DATE)) ) Expands to (newlines added): object< DapiDate >::register_(); BOOST_PP_SEQ_FOR_EACH( CXXEXT_DECLARE_PROPERTY_SEQ , ~ , ((DapiDate, year, IS_LONG, 0)) ((DapiDate, month, IS_LONG, 0)) ((DapiDate, day, IS_LONG, 0)) ) Which is an intermediate expansion of the above listed DAPHP_REGISTER_CLASS(DapiDate, DAPHP_PROPS_DATE). g++ 4.5.0 (MinGW) and MSVC 9 Express behave the same, which makes me believe this is a PEBKAC, but I just don't see it. Why doesn't DAPHP_REGISTER_CLASSES expand all the way as DAPHP_REGISTER_CLASS does? Please enlighten me. -- roman

On 19 June 2011 01:37, Roman Neuhauser <neuhauser@sigpipe.cz> wrote:
Why doesn't DAPHP_REGISTER_CLASSES expand all the way as DAPHP_REGISTER_CLASS does? Please enlighten me.
C macros can't be called recursively. Boost.Preprocessor uses a clever technique to get round that for some macros, but it doesn't seem to do it for BOOST_PP_SEQ_FOR_EACH, I'm not sure why, it might be too expensive to do for every macro. I think that one thing you can do (and this is pretty crummy) is to use BOOST_PP_SEQ_FOR_EACH_I for one of the calls and just ignore the index. Or alternatively you can use a macro that supports recursion, I think BOOST_PP_SEQ_FOLD_LEFT, BOOST_PP_SEQ_FOLD_RIGHT and BOOST_PP_FOR are possibilities.

# dnljms@gmail.com / 2011-06-19 17:45:00 +0100:
On 19 June 2011 01:37, Roman Neuhauser <neuhauser@sigpipe.cz> wrote:
Why doesn't DAPHP_REGISTER_CLASSES expand all the way as DAPHP_REGISTER_CLASS does? Please enlighten me.
C macros can't be called recursively. Boost.Preprocessor uses a clever technique to get round that for some macros, but it doesn't seem to do it for BOOST_PP_SEQ_FOR_EACH, I'm not sure why, it might be too expensive to do for every macro.
Ah, BOOST_PP_SEQ_FOR_EACH Remarks section doesn't include the "Previously, this macro could not be used inside ..." paragraph that's present elsewhere.
I think that one thing you can do (and this is pretty crummy) is to use BOOST_PP_SEQ_FOR_EACH_I for one of the calls and just ignore the index. Or alternatively you can use a macro that supports recursion, I think BOOST_PP_SEQ_FOLD_LEFT, BOOST_PP_SEQ_FOLD_RIGHT and BOOST_PP_FOR are possibilities.
I decided to abstain from using sequences inside the CXXEXT namespace. The inner BOOST_PP_SEQ_FOR_EACH is now BOOST_PP_LIST_FOR_EACH with input transformed by #define CXXEXT_SEQ_TO_LIST(seq) \ BOOST_PP_EXPAND(BOOST_PP_TUPLE_TO_LIST BOOST_PP_SEQ_TO_ARRAY(seq)) -- roman
participants (2)
-
Daniel James
-
Roman Neuhauser