Boost logo

Boost Users :

Subject: Re: [Boost-users] [Preprocessor] Compile error after change from Boost 1.55 to 1.57
From: Edward Diener (eldiener_at_[hidden])
Date: 2015-02-27 10:27:49


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 <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_at_[hidden]
>> http://lists.boost.org/mailman/listinfo.cgi/boost-users
>>


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net