On 2/27/2015 9:56 AM, Edward Diener wrote:
On 2/27/2015 5:04 AM, Franz Alt wrote:
Hi,
I've written some preprocessor directives to generate functions for a class. With Boost 1.55 everything works fine with gcc and clang. When I try to change to Boost 1.57 I've got some strange compile errors.
I'm happy if someone could help.
In your FUNCTION_DECL macro you have this line:
BOOST_PP_IF(BOOST_PP_LIST_IS_NIL(BOOST_PP_TUPLE_TO_LIST(BOOST_PP_TUPLE_ELEM(1, tup))), \
but with your second function of '(b)' there is only one tuple element so attempting BOOST_PP_TUPLE_ELEM(1,tup) on it is undefined behavior. Instead test the size of the tuple with BOOST_PP_TUPLE_SIZE and if it is only 1 then you know you don't have a second tuple element and can convert it to '()'. In other words instead of:
BOOST_PP_IF(BOOST_PP_LIST_IS_NIL(BOOST_PP_TUPLE_TO_LIST(BOOST_PP_TUPLE_ELEM(1, tup))), \ (), \
have
BOOST_PP_IIF(BOOST_PP_EQUAL(BOOST_PP_TUPLE_SIZE(tup),1)), \ (), \
This should be: BOOST_PP_IIF(BOOST_PP_EQUAL(BOOST_PP_TUPLE_SIZE(tup),1), \ (), \ Also your BOOST_PP_SEQ_TO_TUPLE( \ BOOST_PP_SEQ_TRANSFORM( \ ADD_CONST_REF, \ _, \ BOOST_PP_TUPLE_TO_SEQ(BOOST_PP_LIST_TO_TUPLE(BOOST_PP_TUPLE_TO_LIST(BOOST_PP_TUPLE_ELEM(1, tup)))) \ ) \ ) \ has to be moved to another macro since it is evaluated even when your 'tup' only has a single element. Correct is: #define FUNCTION_DECL_EMPTY(tup) () #define FUNCTION_DECL_NOT_EMPTY(tup) \ BOOST_PP_SEQ_TO_TUPLE( \ BOOST_PP_SEQ_TRANSFORM( \ ADD_CONST_REF, \ _, \ BOOST_PP_TUPLE_TO_SEQ(BOOST_PP_LIST_TO_TUPLE(BOOST_PP_TUPLE_TO_LIST(BOOST_PP_TUPLE_ELEM(1, tup)))) \ ) \ ) #define FUNCTION_DECL(r, data, tup) \ double BOOST_PP_TUPLE_ELEM(0, tup) \ BOOST_PP_IIF(BOOST_PP_EQUAL(BOOST_PP_TUPLE_SIZE(tup),1), \ FUNCTION_DECL_EMPTY, \ FUNCTION_DECL_NOT_EMPTY \ ) (tup) \ const;
You can't rely on undefined behavior and your version relies on BOOST_PP_TUPLE_ELEM on an element which does not exist return nothing and on BOOST_PP_TUPLE_TO_LIST when presented with nothing for a tuple expanding to an empty list.
The fact that this once worked is just a coincidence of the implementation details, and these have changed from 1.55 to 1.57.
Thanks
Franz
gcc 4.9.1 failed with error:
test.cpp:33:1: error: macro "BOOST_PP_SEQ_ELEM_III" requires 2 arguments, but only 1 given ) ^ test.cpp:33:1: error: macro "BOOST_PP_VARIADIC_ELEM_2" requires 4 arguments, but only 2 given test.cpp:60:1: error: macro "BOOST_PP_SEQ_ELEM_III" requires 2 arguments, but only 1 given MY_FUNCTION_BEGIN((b)) ^ test.cpp:60:1: error: macro "BOOST_PP_VARIADIC_ELEM_2" requires 4 arguments, but only 2 give
clang 3.5.0 failed with error:
test.cpp:30:3: error: too few arguments provided to function-like macro invocation MY_FUNCTIONS( \ ^ test.cpp:25:25: note: expanded from macro 'MY_FUNCTIONS' BOOST_PP_SEQ_FOR_EACH(FUNCTION_DECL, _, seq) ^ ..../boost.1_57_0/boost/preprocessor/seq/for_each.hpp:26:67: note: expanded from macro 'BOOST_PP_SEQ_FOR_EACH' # define BOOST_PP_SEQ_FOR_EACH(macro, data, seq) BOOST_PP_FOR((macro, data, seq (nil)), BOOST_PP_SEQ_FOR_EACH_P, BOOST_PP_SEQ_FOR_EACH_O, BOOST_PP_SEQ_FOR_EACH_M) ^
..../boost.1_57_0/boost/preprocessor/repetition/detail/for.hpp:22:78: note: expanded from macro 'BOOST_PP_FOR_1' # define BOOST_PP_FOR_1(s, p, o, m) BOOST_PP_FOR_1_C(BOOST_PP_BOOL(p(2, s)), s, p, o, m)
^ note: (skipping 18 expansions in backtrace; use -fmacro-backtrace-limit=0 to see all) packages/boost/boost_i4/boost/preprocessor/seq/elem.hpp:22:39: note: expanded from macro 'BOOST_PP_SEQ_ELEM' # define BOOST_PP_SEQ_ELEM(i, seq) BOOST_PP_SEQ_ELEM_I(i, seq) ^ packages/boost/boost_i4/boost/preprocessor/seq/elem.hpp:41:45: note: expanded from macro 'BOOST_PP_SEQ_ELEM_I' # define BOOST_PP_SEQ_ELEM_I(i, seq) BOOST_PP_SEQ_ELEM_II(BOOST_PP_SEQ_ELEM_ ## i seq) ^ packages/boost/boost_i4/boost/preprocessor/seq/elem.hpp:43:62: note: expanded from macro 'BOOST_PP_SEQ_ELEM_II' # define BOOST_PP_SEQ_ELEM_II(im) BOOST_PP_SEQ_ELEM_III(im) ^ packages/boost/boost_i4/boost/preprocessor/seq/elem.hpp:44:13: note: macro 'BOOST_PP_SEQ_ELEM_III' defined here # define BOOST_PP_SEQ_ELEM_III(x, _) x
The program is:
#include <iostream>
#ifndef BOOST_PP_VARIADICS #define BOOST_PP_VARIADICS #endif
#include
#define ADD_CONST_REF(op, data, elem) elem const &
#define FUNCTION_DECL(r, data, tup) \ double BOOST_PP_TUPLE_ELEM(0, tup) \
BOOST_PP_IF(BOOST_PP_LIST_IS_NIL(BOOST_PP_TUPLE_TO_LIST(BOOST_PP_TUPLE_ELEM(1,
tup))), \ (), \ BOOST_PP_SEQ_TO_TUPLE( \ BOOST_PP_SEQ_TRANSFORM( \ ADD_CONST_REF, \ _, \
BOOST_PP_TUPLE_TO_SEQ(BOOST_PP_LIST_TO_TUPLE(BOOST_PP_TUPLE_TO_LIST(BOOST_PP_TUPLE_ELEM(1,
tup)))) \ ) \ ) \ ) \ const;
#define MY_FUNCTIONS(seq) \ BOOST_PP_SEQ_FOR_EACH(FUNCTION_DECL, _, seq)
class Foo { public: MY_FUNCTIONS( \ ((a, (int))) \ ((b) ) \ ) };
#define ADD_ARG(op, data, elem) elem const & BOOST_PP_CAT(a_, elem)
#define MY_FUNCTION_BEGIN(tup) \ double Foo::BOOST_PP_TUPLE_ELEM(0, tup) \
BOOST_PP_IF(BOOST_PP_LIST_IS_NIL(BOOST_PP_TUPLE_TO_LIST(BOOST_PP_TUPLE_ELEM(1,
tup))), \ (), \ BOOST_PP_SEQ_TO_TUPLE( \ BOOST_PP_SEQ_TRANSFORM( \ ADD_ARG, \ _, \
BOOST_PP_TUPLE_TO_SEQ(BOOST_PP_LIST_TO_TUPLE(BOOST_PP_TUPLE_TO_LIST(BOOST_PP_TUPLE_ELEM(1,
tup)))) \ ) \ ) \ ) const \ {
#define MY_FUNCTION_END() }
MY_FUNCTION_BEGIN((a, (int))) { std::cout << "Foo::a(" << a_int << ")\n"; } MY_FUNCTION_END()
MY_FUNCTION_BEGIN((b)) { std::cout << "Foo::b()\n"; } MY_FUNCTION_END()
int main() { Foo f; f.a(42); f.b();
return 0; }
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users