Boost logo

Boost Users :

Subject: Re: [Boost-users] Preprocessor: Expaning empty VA_ARGS
From: Edward Diener (eldiener_at_[hidden])
Date: 2016-09-09 12:16:49


On 9/9/2016 4:35 AM, Florian Lindner wrote:
> Am 08.09.2016 um 18:06 schrieb Edward Diener:
>> On 9/8/2016 10:35 AM, Florian Lindner wrote:
>>> Hello,
>>>
>>> I have this preprocessor macros:
>>>
>>> -----------
>>>
>>> #include <boost/preprocessor/variadic/to_seq.hpp>
>>> #include <boost/preprocessor/seq/for_each_i.hpp>
>>> #include <boost/preprocessor/stringize.hpp>
>>>
>>> #include <iostream>
>>>
>>> #define TRACE(...) \
>>> std::cout << "foo" \
>>> BOOST_PP_SEQ_FOR_EACH_I(LOG_ARGUMENT,, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__));
>>>
>>> #define LOG_ARGUMENT(r, data, i, elem) \
>>> << std::endl << " Argument " << i << ": " << BOOST_PP_STRINGIZE(elem) << " == " << elem
>>>
>>>
>>> int main(int argc, char *argv[])
>>> {
>>> TRACE();
>>>
>>> return 0;
>>> }
>>>
>>> -----------
>>>
>>> They compile when TRACE has arguments, but not without. Problem is, that LOG_ARGUMENT is called even when no args are
>>> supplied, leading to the expansion:
>>>
>>> std::cout << "foo" << std::endl << " Argument " <<
>>> 0
>>> << ": " << "" << " == " << ;;
>>>
>>> elem is empty, therefore there is no expression after the last <<
>>>
>>> expected primary-expression before »;« token
>>>
>>> How can I deal with that?
>>
>> You do have variadic data, only the single variadic data element is empty. So the idea is to check for emptiness. You
>> can do that with my VMD library and the BOOST_VMD_IS_EMPTY macro.
>>
>> Your preprocessing logic path should be:
>>
>> 1) Retrieve the first variadic element using BOOST_PP_VARIADIC_ELEM(0,__VA_ARGS__).
>>
>> 2) Check for emptiness of what you retrieved using BOOST_VMD_IS_EMPTY.
>>
>> 3) If it is not empty proceed with what you are doing above, else output nothing.
>>
>> I will presume you know enough about BOOST_PP control constructs to figure out the rest.
>
> Hey,
> thanks for your input, from which I deviated slightly. The code looks like that now:
>
> #include <boost/preprocessor/variadic/to_seq.hpp>
> #include <boost/preprocessor/seq/for_each_i.hpp>
> #include <boost/preprocessor/stringize.hpp>
> #include <boost/preprocessor/facilities/empty.hpp>
>
> #include <boost/vmd/is_empty.hpp>
>
> #include <iostream>
>
> #define TRACE(...) \
> std::cout << "foo" \
> BOOST_PP_IF(BOOST_VMD_IS_EMPTY(__VA_ARGS__), \
> BOOST_PP_EMPTY(), \
> BOOST_PP_SEQ_FOR_EACH_I(LOG_ARGUMENT,, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__)));
>
> #define LOG_ARGUMENT(r, data, i, elem) \
> << std::endl << " Argument " << i << ": " << BOOST_PP_STRINGIZE(elem) << " == " << elem
>
>
> int main(int argc, char *argv[])
> {
> int i = 5;
> std::string s = "fünf";
> TRACE();
> TRACE("args1", 5, s);
>
> return 0;
> }
>
> Output is:
>
> foofoo
> Argument 0: "args1" == args1
> Argument 1: 5 == 5
> Argument 2: s == fünf%
>
> Missing newlines are ok, in real application the output is written on a BOOST_LOG stream which adds newlines.
>
> Do you see any problems with that?
>
>
>> I could add a macro in VMD to check if variadic data is "empty".
>
> It looks like it works just fine.

Yes it does. I forgot that you can just pass the variadic data to the
BOOST_VMD_IS_EMPTY macro, even after I write that macro myself <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