Boost logo

Boost :

Subject: Re: [boost] Review Request: Variadic Macro Data library
From: Edward Diener (eldiener_at_[hidden])
Date: 2011-02-20 20:25:43


On 2/19/2011 10:48 AM, Lorenzo Caminiti wrote:
> On Fri, Feb 18, 2011 at 9:58 PM, Edward Diener<eldiener_at_[hidden]> wrote:
>> On 2/18/2011 7:27 PM, Lorenzo Caminiti wrote:
>>>
>>> On Thu, Feb 17, 2011 at 5:13 PM, Edward Diener<eldiener_at_[hidden]>
>>> wrote:
>>>>
>>>> I am requesting that my library, the Variadic Macro Data library, which
>>>> is
>>>> in the sandbox in the variadic_macro_data directory, be reviewed for
>>>> inclusion into Boost.
>>>>
>>>> The variadic_macro_data library adds support and functionality for
>>>> variadic
>>>> macros to Boost as well as integrating variadic macros with the Boost PP
>>>> library without changing the latter library in any way.
>>>>
>>>> I believe others have used my library, can attest to its quality and that
>>>> it
>>>> does what it is supposed to do. and have found it useful when using
>>>> variadic
>>>> macros with Boost PP. I myself have used its functionality in my own TTI
>>>> library in the sandbox. Support for variadic macros is implemented in
>>>> nearly
>>>> all modern C++ compilers and the syntax is natural for an end-user. The
>>>> library is finalized as far as functionality is concerned and I would
>>>> like
>>>> to see it in Boost and am willing to maintain it as a Boost library.
>>>
>>> Is it possible to use variadic macros to detect empty parameters?
>>
>> My understanding of variadic macro data is that at least one parameter must
>> be specified.
>>
>>>
>>> For example:
>>>
>>> #include<boost/variadic_macro_data/VariadicMacroData.hpp> // Proposed
>>> lib.
>>>
>>> VMD_DATA_SIZE(1, 2) // 2
>>> VMD_DATA_SIZE(1) // 1
>>> VMD_DATA_SIZE() // 1 not 0 :((
>>>
>>> But I would like to the last size to expand to 0 (or have a different
>>> macro that would expand to 0 in that case).
>>>
>>> With a real C99 preprocessor (e.g., GCC) I can do the following
>>> because empty macro parameters are supported:
>>
>> Are they for variadic macro data in C++ ?
>
> I think variadics and empty macro parameters are different things. C99
> preprocessor (e.g., GCC) supports both while MSVC only supports
> variadics. That is why I was wondering if variadics can be used to
> detect empty macro parameters so I can do so also on MSVC.
>
> On Mon, Sep 6, 2010 at 3:29 PM, Paul Mensonides<pmenso57_at_[hidden]> wrote:
>> ...
>> However, IS_EMPTY is _not_ a macro for general-purpose emptiness detection.
>> Its implementation requires the concatenation of an identifier to the front
>> of the argument which rules out all arguments for which that isn't valid.
>> For example, IS_EMPTY(+) is undefined behavior according to all revisions
>> of both the C and C++ standards (including the forthcoming C++0x). Thus, at
>> minimum, the argument must be an identifier (or keyword--same thing at this
>> point) or a numeric literal that doesn't contain a decimal point.
>>
>> It is
>> valid (and has been since C90) to pass something that expands to nothing as
>> an argument to a macro. However, it is not valid to pass nothing. E.g.
>
> See http://lists.boost.org/Archives/boost/2010/09/170639.php
>
>> I will look at that and see what I can come up with. If variadic macros
>> support an empty parameter list, I should provide a correct size of 0. If it
>> does not I should indicate an error. So either way I will look to make a
>> correction. Thanks for pointing this out.
>
> This works on both MSVC and GCC :) Does it work on other
> preprocessors? Can anyone please check?
>
> #include<boost/variadic_macro_data/VariadicMacroData.hpp> // Proposed
> lib in Boost's sandbox.
> #include<boost/preprocessor.hpp>
> #include<boost/preprocessor/facilities/is_empty.hpp>
>
> VMD_DATA_SIZE(1, 2) // 2
> VMD_DATA_SIZE(1) // 1
> VMD_DATA_SIZE() // 1 not 0 :((
>
> #define PP_VA_EAT(...) /* must expand to nothing */
>
> #define PP_VA_SIZE_1OR0_(maybe_empty) \
> BOOST_PP_IIF(BOOST_PP_IS_EMPTY(maybe_empty (/*exapnd empty */) ), 0, 1)
>
> #define PP_VA_SIZE_(size, ...) \
> BOOST_PP_IIF(BOOST_PP_EQUAL(size, 1), \
> PP_VA_SIZE_1OR0_ \
> , \
> size PP_VA_EAT \
> )(__VA_ARGS__ BOOST_PP_EMPTY)
>
> #define PP_VA_SIZE(...) PP_VA_SIZE_(VMD_DATA_SIZE(__VA_ARGS__), __VA_ARGS__)
>
> PP_VA_SIZE(1, 2) // 2
> PP_VA_SIZE(1) // 1
> PP_VA_SIZE() // 0 :))

This does not work under gcc or msvc:

#include <boost/variadic_macro_data/vmd.hpp>
#include <boost/preprocessor.hpp>
#include <boost/preprocessor/facilities/is_empty.hpp>

#if !defined(BOOST_NO_VARIADIC_MACROS)

#define PP_VA_EAT(...) /* must expand to nothing */
#define PP_VA_SIZE_1OR0_(maybe_empty) \
BOOST_PP_IIF(BOOST_PP_IS_EMPTY(maybe_empty (/*exapnd empty */) ), 0, 1)
#define PP_VA_SIZE_(size, ...) \
     BOOST_PP_IIF(BOOST_PP_EQUAL(size, 1), \
         PP_VA_SIZE_1OR0_ \
     , \
         size PP_VA_EAT \
     )(__VA_ARGS__ BOOST_PP_EMPTY)
#define PP_VA_SIZE(...) \
PP_VA_SIZE_(VMD_DATA_SIZE(__VA_ARGS__), __VA_ARGS__)

#endif

int main()
   {
   int j = PP_VA_SIZE(2);
   return 0;
   }

gcc:

"...patience...
...found 319 targets...
...updating 4 targets...
gcc.compile.c++
..\..\..\bin.v2\libs\variadic_macro_data\test\test_data_try.test\gcc-mingw-4.5.2\debug\test_data_try.o
test_data_try.cpp: In function 'int main()':
test_data_try.cpp:23:11: error:
'BOOST_PP_IIF_BOOST_PP_COMPL_BOOST_PP_NOT_EQUAL_CHECK_BOOST_PP_NOT_EQUAL_VMD_DATA_SIZE'
was not declared in this scope
test_data_try.cpp:23:1: error: 'BOOST_PP_NOT_EQUAL_1' was not declared
in this scope
test_data_try.cpp:12:9: error: 'PP_VA_SIZE_1OR0_' was not declared in
this scope
test_data_try.cpp:23:11: error: 'VMD_DATA_SIZE' was not declared in this
scope
test_data_try.cpp:23:11: error: expected ')' before 'BOOST_PP_EMPTY'
test_data_try.cpp:23:7: warning: unused variable 'j'

     "g++" -ftemplate-depth-128 -O0 -fno-inline -Wall -pedantic -g
-Wno-variadic-macros -I"..\..\.."
-I"C:\Programming\VersionControl\boost" -c -o
"..\..\..\bin.v2\libs\variadic_macro_data\test\test_data_try.test\gcc-mingw-4.5.2\debug\test_data_try.o"
"test_data_try.cpp"

...failed gcc.compile.c++
..\..\..\bin.v2\libs\variadic_macro_data\test\test_data_try.test\gcc-mingw-4.5.2\debug\test_data_try.o...

msvc:

"...patience...
...found 331 targets...
...updating 5 targets...
compile-c-c++
..\..\..\bin.v2\libs\variadic_macro_data\test\test_data_try.test\msvc-10.0\debug\threading-multi\test_data_try.obj
test_data_try.cpp
test_data_try.cpp(23) : error C2065: 'BOOST_PP_NOT_EQUAL_1' : undeclared
identifier
test_data_try.cpp(23) : error C2065: 'PP_VA_SIZE_1OR0_' : undeclared
identifier
test_data_try.cpp(23) : error C2146: syntax error : missing ')' before
identifier 'PP_VA_EAT'
test_data_try.cpp(23) : error C3861:
'BOOST_PP_IIF_BOOST_PP_COMPL_BOOST_PP_NOT_EQUAL_CHECK_BOOST_PP_NOT_EQUAL_VMD_DATA_SIZE':
identifier not found
test_data_try.cpp(23) : error C3861: 'VMD_DATA_SIZE': identifier not found
test_data_try.cpp(23) : error C2059: syntax error : ')'

     call "C:\Program Files (x86)\Microsoft Visual Studio
10.0\VC\vcvarsall.bat" x86 >nul
cl /Zm800 -nologo
@"..\..\..\bin.v2\libs\variadic_macro_data\test\test_data_try.test\msvc-10.0\debug\threading-multi\test_data_try.obj.rsp"

...failed compile-c-c++
..\..\..\bin.v2\libs\variadic_macro_data\test\test_data_try.test\msvc-10.0\debug\threading-multi\test_data_try.obj...

My own best try at a CHECK_EMPTY macro so far is:

#include <boost/variadic_macro_data/vmd.hpp>
#include <boost/preprocessor.hpp>

#if !defined(BOOST_NO_VARIADIC_MACROS)

#define CAT_ONE(...) VMD_DETAIL_CAT(1,__VA_ARGS__)
#define CHECK_EMPTY(...) \
   BOOST_PP_IIF \
     ( \
     BOOST_PP_EQUAL(1,BOOST_VMD_DATA_SIZE(CAT_ONE(__VA_ARGS__))), \
     BOOST_PP_EQUAL(1,BOOST_VMD_DATA_ELEM(0,CAT_ONE(__VA_ARGS__))), \
     0 \
     ) \
/**/

#endif

int main()
   {
   int i = CHECK_EMPTY();
   int j = CHECK_EMPTY(1);
   int k = CHECK_EMPTY(a,b,c);
// int m = CHECK_EMPTY(a);
   return 0;
   }

The idea is to paste '1' the front of the variadic macro data sequence
and if there is just '1' as the size and the token is '1', the sequence
must have been empty to begin with.

This works correctly returning 1 for i and a 0 for j or k until I
uncomment the 'int m' line. Evidently one can not do BOOST_PP_EQUAL if
one of the parameters is not a number.

I get on msvc:

...patience...
...found 329 targets...
...updating 5 targets...
compile-c-c++
..\..\..\bin.v2\libs\variadic_macro_data\test\test_data_try.test\msvc-10.0\debug\threading-multi\test_data_try.obj
test_data_try.cpp
test_data_try.cpp(24) : error C2065: 'BOOST_PP_NIL' : undeclared identifier
test_data_try.cpp(24) : error C3861:
'BOOST_PP_COMPL_BOOST_PP_NOT_EQUAL_CHECK_BOOST_PP_NOT_EQUAL_1a':
identifier not found

     call "C:\Program Files (x86)\Microsoft Visual Studio
10.0\VC\vcvarsall.bat" x86 >nul
cl /Zm800 -nologo
@"..\..\..\bin.v2\libs\variadic_macro_data\test\test_data_try.test\msvc-10.0\debug\threading-multi\test_data_try.obj.rsp"

...failed compile-c-c++
..\..\..\bin.v2\libs\variadic_macro_data\test\test_data_try.test\msvc-10.0\debug\threading-multi\test_data_try.obj...

and on gcc:

...patience...
...found 317 targets...
...updating 4 targets...
gcc.compile.c++
..\..\..\bin.v2\libs\variadic_macro_data\test\test_data_try.test\gcc-mingw-4.5.2\debug\test_data_try.o
test_data_try.cpp:21:23: warning: invoking macro CHECK_EMPTY argument 1:
empty macro arguments are undefined in ISO C90 and ISO C++98
test_data_try.cpp:21:23: warning: invoking macro CHECK_EMPTY argument 1:
empty macro arguments are undefined in ISO C90 and ISO C++98
test_data_try.cpp:21:23: warning: invoking macro CAT_ONE argument 1:
empty macro arguments are undefined in ISO C90 and ISO C++98
test_data_try.cpp:21:23: warning: invoking macro VMD_DETAIL_CAT argument
2: empty macro arguments are undefined in ISO C90 and ISO C++98
test_data_try.cpp:21:23: warning: invoking macro
VMD_DETAIL_PRIMITIVE_CAT argument 2: empty macro arguments are undefined
in ISO C90 and ISO C++98
test_data_try.cpp:21:1: warning: invoking macro CAT_ONE argument 1:
empty macro arguments are undefined in ISO C90 and ISO C++98
test_data_try.cpp:21:1: warning: invoking macro VMD_DETAIL_CAT argument
2: empty macro arguments are undefined in ISO C90 and ISO C++98
test_data_try.cpp:21:1: warning: invoking macro VMD_DETAIL_PRIMITIVE_CAT
argument 2: empty macro arguments are undefined in ISO C90 and ISO C++98
test_data_try.cpp: In function 'int main()':
test_data_try.cpp:24:1: error: 'BOOST_PP_NIL' was not declared in this scope
test_data_try.cpp:24:1: error:
'BOOST_PP_COMPL_BOOST_PP_NOT_EQUAL_CHECK_BOOST_PP_NOT_EQUAL_1a' was not
declared in this scope
test_data_try.cpp:21:7: warning: unused variable 'i'
test_data_try.cpp:22:7: warning: unused variable 'j'
test_data_try.cpp:23:7: warning: unused variable 'k'
test_data_try.cpp:24:7: warning: unused variable 'l'

     "g++" -ftemplate-depth-128 -O0 -fno-inline -Wall -pedantic -g
-Wno-variadic-macros -I"..\..\.."
-I"C:\Programming\VersionControl\boost" -c -o
"..\..\..\bin.v2\libs\variadic_macro_data\test\test_data_try.test\gcc-mingw-4.5.2\debug\test_data_try.o"
"test_data_try.cpp"

...failed gcc.compile.c++
..\..\..\bin.v2\libs\variadic_macro_data\test\test_data_try.test\gcc-mingw-4.5.2\debug\test_data_try.o..."

I think Paul Mensonides may be right and there is no foolproof way to
check for a completely empty parameter list even using variadic macros.
Further ideas ?


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk