Hi Edward,

you're right. I think I've oversight this fact.

Thanks!

2015-02-27 15:56 GMT+01:00 Edward Diener <eldiener@tropicsoft.com>:
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)), \
   (), \

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 <boost/preprocessor.hpp>

     #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



_______________________________________________
Boost-users mailing list
Boost-users@lists.boost.org
http://lists.boost.org/mailman/listinfo.cgi/boost-users