Boost logo

Boost Users :

Subject: Re: [Boost-users] Preprocessor: Expaning empty VA_ARGS
From: Florian Lindner (mailinglists_at_[hidden])
Date: 2016-09-09 04:35:59


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.

Best,
Florian


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