Boost logo

Boost :

Subject: Re: [boost] Review Request: Variadic Macro Data library
From: Edward Diener (eldiener_at_[hidden])
Date: 2011-02-19 12:35:39


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

Thanks for the clarification.

>
>> 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 :))

Thanks for this code. I will try to see if it works, and also try to
test it on compilers other than gcc and VC++. If it does, I will
incorporate it in order to return a size of 0 when the parameter list is
empty if that is the correct thing to do. OTOH if it is illegal for
variadic macros to take an empty parameter list, which seems to be the
case, it would be better to see if I can generate an error, even if the
compiler allows it.

>
> The strange thing about this code is that `PP_VA_SIZE()` as well as
> `VMD_DATA_SIZE()` don't give an error in the first place. They should
> error because they are passed with an empty macro parameter (which is
> not legal). It would have been legal instead to pass a parameter
> expanding to empty like in `PP_VA_SIZE(BOOST_PP_EMPTY())` or
> `VMD_DATA_SIZE(BOOST_PP_EMPTY())`.
>
> Why `PP_VA_SIZE()` and `VMD_DATA_SIZE()` accept empty macro parameter?
> Is that a variadic macros' feature or a MSVC bug?

I am not sure if it is a compiler bug or not. I will look at the problem
and see what I can do. BTW there has already been an updated version of
the variadic_macro_data library in the sandbox now ( version 1.3 ) which
changes no functionality but which follows Boost naming conventions (
and also conveniently shortens the name of the header file to vmd.hpp ).

>
>> From http://www.open-std.org/JTC1/SC22/WG14/www/docs/C99RationaleV5.10.pdf
> There must be at least one argument to match the ellipsis. This
> requirement avoids the problems
> that occur when the trailing arguments are included in a list of
> arguments to another macro or
> function. For example, if dprintf had been defined as
> 10 #define dprintf(format, ...) \
> dfprintf(stderr, format, _ _VA_ARGS_ _)
> and it were allowed for there to be only one argument, then there
> would be a trailing comma in
> the expanded form. While some implementations have used various
> notations or conventions to
> work around this problem, the Committee felt it better to avoid the
> problem altogether.
> 15 Similarly, the _ _VA_ARGS_ _ notation was preferred to other
> proposals for this syntax.
> A new feature of C99: Function-like macro invocations may also now
> have empty arguments,
> that is, an argument may consist of no preprocessing tokens. In C89,
> any argument that
> consisted of no preprocessing tokens had undefined behavior, but was
> noted as a common
> extension.
> 20 A function-like macro invocation f() has the form of either a call
> with no arguments or a call
> with one empty argument. Which form it actually takes is determined
> by the definition of f,
> which indicates the expected number of arguments.
>
>>> BTW, a few minor comments on you library:
>>> 1) I think a name like BOOST_PP_VA_... is better than BOOST_VMD. "VA"
>>> is the same abbreviation for variadics that C99 uses in __VA_ARGS__
>>> and Boost.Preprocessor already uses abbreviations like in
>>> BOOST_PP_SEQ.
>>
>> What does the BOOST_PP_SEQ abbreviation have to do with BOOST_VMD_ ?
>
> I was pointing out hat Boost.Preprocessor already uses some
> abbreviation so "VARIADICS" doesn't necessarily need to be spelled out
> completely.

OK, understood. I try to keep the names short in my libraries if I can.

>
>>> Alternatively, I would consider BOOST_PP_VARIADICS_...
>>> but still not "VMD" because programmers will not know what VMD stands
>>> for.
>>
>> I used VMD to represent (V)ariadic(M)acro(D)ata, which is really what my
>> library is about and also integrating that data with Boost PP. I rejected VA
>> because its connotation in C++ is "variable argument(s)" and my library is
>
> I think __VA_ARGS__ stands for VAriadics ARGumentS so VA only
> abbreviates VAriadics. However, I couldn't find an actual standard
> reference that explicitly defines what the word __VA_ARGS__ stands
> for.

It is not that important. VMD expresses what I want, VA does not.

>
>> about manipulating variadic macro data. I feel that something like VARIADICS
>> is too long but I would certainly agree to it if others found it more
>> expressive. I also do not want it to be BOOST_PP_ anything unless others
>> decide it should be part of Boost PP and not its own library, and in that
>> case I feel Paul Mensonides would need to find that acceptable.
>
> IMO, library users would expect your library to be part of
> Boost.Preprocessor. It's like adding another data set to
> Boost.Preprocessor for variadics.

I do not agree with this, although I understand the reasoning. I do not
think one can just add to another library, even if one does something
which in itself is an addition/extension to another library's
implementation, without the other library programmer's approval. If it
were decided that the VMD library were to become a part of Boost PP, and
Paul Mensonides approved that, I would have no problem making it so.

>
>>> 2) I would add PP_VA_EAT, PP_VA_IDENTITY, PP_VA_CAT (similar to what
>>> they do already in Boost.Preprocessor and they should be trivial to
>>> implement). Also, I would add `#define PP_VA_SAME(...) __VA_ARGS__`.
>>
>> I am willing to add functionality to the library but I wonder where that
>> would stop. Essentially variadic macro data is similar to any of the other
>
> I agree, no point in duplicating Boost.Preprocessor API. However, in
> using your library even just a bit I needed things like PP_VA_EAT,
> PP_VA_IDENTITY, PP_VA_CAT to program control statements like
> BOOST_PP_IIF, etc. While all of these are trivial to implement, it
> would be annoying to to re-implement all these facility macros all the
> times... It would be interesting to know what other programmer
> experience is in using your library to decide which Boost.Preprocessor
> control and facility macros are the most commonly used with variadics
> arguments.

I agree with that. I am of course willing to add some basic facilities.
But I still think that you should think about converting variadic macro
data to another functionally richer Boost PP data type first before you
do anything else with the data.

>
>> data types in Boost PP in that it is really just a separate data type. Since
>> the Boost PP data types already have a rich set of functionality I sort of
>> feel that duplicating any of that functionality for variadic data itself
>> will be redundant. This is especially true as my library has support for
>> converting back and forth variadic data to any of the Boost PP data types. I
>> feel pretty strongly that the use of variadic data with Boost PP should
>> really be to provide a more pleasant syntax for the end-user, but once the
>> programmer handles the variadic data he should convert it to a Boost PP data
>> simply because that data type already has a rich set of functionality for
>> dealing with the data.
>>
>> I would be willing to add BOOST_VMD_CAT and BOOST_VMD_IDENTITY since they
>> are both trivial ( just call to the appropiate BOOST_PP_ macros passing
>> __VA_ARGS__ ). Your last is just __VA_ARGS__ as you show. But I really
>
> I often do:
>
> #define DO_(p) // do something wiht p...
> #define DO(cond, p) BOOST_PP_IIF(cond, DO_, p BOOST_PP_TUPLE_EAT(1))(p)

Convert variadic macro data to a Boost PP tuple with
BOOST_VMD_DATA_TO_PP_TUPLE(...) and then you can manipulate the result
as a tuple as above. Sure it is an extra step but, as I said previously,
I think it is a mistake to try to duplicate any of the functionality of
the much more functional Boost PP data types. Of course I can try to do
it if people want to work with variadic data directly, but considering
how much richer in functionality the Boost PP data types already are it
just does not seem worthwhile to do, and would end up being a great deal
of work for little actual purpose.

>
> But I can't do this with variadic p because the IF will have too many
> arguments is p is __VA_ARGS__. So SAME() would be handy:
>
> #define PP_VA_SAME(...) __VA_ARGS__
> #define DO_(...) // do something with __VA_ARGS__...
> #define DO(cond, ...) BOOST_PP_IIF(cond, DO_, PP_VA_SAME)(__VA_ARGS__)
>
>> wonder if more functionality on variadic macro data is really worth it
>> considering that the goal of the library, other than letting the end-user
>> access individual tokens in the variadic macro data itself, is to convert
>> back and forth to the Boost PP data types. I can understand that an end-user
>> of the library such as yourself might want a number of additional operations
>> on the variadic macro data itself, but I think if you look at the Boost PP
>> data types you will see that their rich functionality offers most anything
>> one would want to do with the data once you get it.


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