Boost logo

Boost Users :

Subject: Re: [Boost-users] Looping through variadic macro arguments
From: Edward Diener (eldiener_at_[hidden])
Date: 2016-03-24 11:00:57


On 3/24/2016 4:42 AM, Florian Lindner wrote:
>
>
> On Wed, 23 Mar 2016 11:56:25 -0400
> Edward Diener <eldiener_at_[hidden]> wrote:
>
>> On 3/23/2016 11:45 AM, Florian Lindner wrote:
>>> Hello,
>>>
>>> another question: I was expecting that the line
>>>
>>> BOOST_PP_SEQ_FOR_EACH_I(PRINT_ARGUMENT,,
>>> BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__));
>>>
>>> in a macro #define vm(expr, ...) expands to nothing, when the the
>>> macro is called with just one argument vm(false), but it fails,
>>> only when called with just one argument:
>>>
>>> % g++ -std=c++11 -g3 test.cpp
>>>
>>> test.cpp: In function 'void f(int)':
>>> test.cpp:109:51: error: expected primary-expression before '<<'
>>> token std::cerr << " Argument " << i << ": " << elem << std::endl;
>>> ^
>>> /usr/include/boost/preprocessor/seq/for_each_i.hpp:85:66: note: in
>>> expansion of macro 'PRINT_ARGUMENT' # define
>>> BOOST_PP_SEQ_FOR_EACH_I_M_I(r, macro, data, seq, i, sz) macro(r,
>>> data, i, BOOST_PP_SEQ_HEAD(seq)) ^ test.cpp:140:1: note: in
>>> expansion of macro 'assertion' assertion(!true);
>>> ^
>>>
>>>
>>> Is there any way to make it work like that?
>>
>> When you specify '...' to indicate variadic arguments you must always
>> supply at least one argument. That's part of the C++ standard.
>>
>> The way to make 'vm' work is to specify:
>>
>> #define vm(...)
>>
>> and then extract your first argument and pass the remaining
>> arguments, if they exist, to your BOOST_PP_SEQ_FOR_EACH_I expansion.
>> I will let you figure out how to do that, but if you find you can't
>> figure it out post back and I will show you the code.
>
> Hey,
>
> ok, I used SEQ_TAIL for that and it works nicely:

That's the solution.

I could add a BOOST_PP_VARIADIC_TAIL but keeping the Boost PP variadic
macros to a minimum was the idea when they were created.

>
> #define PRINT_ARGUMENT(r, data, i, elem) \
> std::cerr << " Argument " << i << ": " << elem << std::endl;
>
> #define assertion(...) if (not BOOST_PP_VARIADIC_ELEM(0, __VA_ARGS__)) { \

Wouldn't

if !(BOOST_PP_VARIADIC_ELEM(0, __VA_ARGS__)) { \

be better ?

> std::cerr << "Assertion in " << __FILE__ << ":" << __LINE__ \
> << ", failed expression: " << BOOST_PP_STRINGIZE(BOOST_PP_VARIADIC_ELEM(0, __VA_ARGS__)) << std::endl; \
> BOOST_PP_SEQ_FOR_EACH_I(PRINT_ARGUMENT,, BOOST_PP_SEQ_TAIL(BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__))); \
> std::cerr.flush(); \
> std::cout.flush(); \
> assert(false); \
> }
>
> as you can see, it's going to be an asssert macro. STRINGIZE gives me the literal expression, like the # operator.
>
> Any comments?

I'm glad Boost PP is useful to you <g>. If you are further interested in
preprocessor programming in general you might find my Boost VMD library
interesting ( shameless plug ) <g>.


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