[config] Support for variadic macros

What is the boost macro which can be used to determine whether or not a compiler supports variadic macros ? I looked at the config macros but could not find the necessary macro documented there.

Zitat von Edward Diener <eldiener@tropicsoft.com>:
What is the boost macro which can be used to determine whether or not a compiler supports variadic macros ? I looked at the config macros but could not find the necessary macro documented there.
there is none to my knowledge. if one is being added, please also take this MSVC bug into account: https://connect.microsoft.com/VisualStudio/feedback/details/521844/variadic-...

On 8/5/2010 5:30 PM, Stefan Strasser wrote:
Zitat von Edward Diener <eldiener@tropicsoft.com>:
What is the boost macro which can be used to determine whether or not a compiler supports variadic macros ? I looked at the config macros but could not find the necessary macro documented there.
there is none to my knowledge.
If there is none, then obviously Boost code can not currently use variadic macros for anything.
if one is being added, please also take this MSVC bug into account: https://connect.microsoft.com/VisualStudio/feedback/details/521844/variadic-...
Welcome to the world of "Unfortunately it does not meet the triage bar for the current release of Visual C++". It's the standard reply in my own experience. No wonder Boost does not worry about using variadic macros yet.

Welcome to the world of "Unfortunately it does not meet the triage bar for the current release of Visual C++". It's the standard reply in my own experience. No wonder Boost does not worry about using variadic macros yet.
Or learn here http://connect.microsoft.com/VisualStudio/feedback/details/385034/preprocess... "Hi: Unfortunately this is the way the Visual C++ preprocessor works and we are unlikely to change it anytime soon." about how Microsoft is determined to keep their VC preprocessor well out of the way of any standard. [The bug misses the then 18-years old C90 standard] Cheers Wolf -- GRATIS für alle GMX-Mitglieder: Die maxdome Movie-FLAT! Jetzt freischalten unter http://portal.gmx.net/de/go/maxdome01

Zitat von Edward Diener <eldiener@tropicsoft.com>:
What is the boost macro which can be used to determine whether or not a compiler supports variadic macros ? I looked at the config macros but could not find the necessary macro documented there.
there is none to my knowledge.
If there is none, then obviously Boost code can not currently use variadic macros for anything.
if one is being added, please also take this MSVC bug into account: https://connect.microsoft.com/VisualStudio/feedback/details/521844/variadic-...
Welcome to the world of "Unfortunately it does not meet the triage bar for the current release of Visual C++". It's the standard reply in my own experience. No wonder Boost does not worry about using variadic macros yet.
someone there has submitted a workaround for this bug. I've tried it, it looks sufficient to implement macros like BOOST_PP_TUPLE_*, but variadic, without the "size" parameter for MSVC (and C99/C++0x)

someone there has submitted a workaround for this bug. I've tried it, it looks sufficient to implement macros like BOOST_PP_TUPLE_*, but variadic, without the "size" parameter for MSVC (and C99/C++0x)
Hi, Variadic macros are part of the C99 standard. Judging from the preprocessor sources, their developers Mr Mensonides (and perhaps Mr Karvonen) seem to have painfully avoided breaking any rule of the C90 standard. For example, there are never empty macro arguments passed, although this would have simplified code in several instances. So, using variadic macros will break downward compatibility. If you think it is time to leave C90 behind, it might be worth evaluating one of the preprocessor engines Chaos (Mensonides) or Order (Karvonen) developed several years ago. Cheers Wolf Lammen -- GMX DSL SOMMER-SPECIAL: Surf & Phone Flat 16.000 für nur 19,99 ¿/mtl.!* http://portal.gmx.net/de/go/dsl

Zitat von Wolf Lammen <ookami1@gmx.de>:
someone there has submitted a workaround for this bug. I've tried it, it looks sufficient to implement macros like BOOST_PP_TUPLE_*, but variadic, without the "size" parameter for MSVC (and C99/C++0x)
Hi,
Variadic macros are part of the C99 standard. Judging from the preprocessor sources, their developers Mr Mensonides (and perhaps Mr Karvonen) seem to have painfully avoided breaking any rule of the C90 standard. For example, there are never empty macro arguments passed, although this would have simplified code in several instances.
So, using variadic macros will break downward compatibility.
I'm not sure I understand what you are saying. I wasn't suggesting to use variadic macros in BOOST_PP_TUPLE_*, I meant new macros _like_ BOOST_PP_TUPLE_*. there are only 6 or so TUPLE macros, and their predominant use is probably: converting a tuple to a sequence. that would effectively introducde a new "data type" to the PP library: a variadic tuple. I'm sure I'm not the first to suggest this, but with the workaround submitted to that microsoft site MSVC can be supported (along with all compilers implementing (conforming) C99 variadic macros)
If you think it is time to leave C90 behind, it might be worth
no I don't.

Variadic macros are part of the C99 standard. Judging from the preprocessor sources, their developers Mr Mensonides (and perhaps Mr Karvonen) seem to have painfully avoided breaking any rule of the C90 standard. For example, there are never empty macro arguments passed, although this would have simplified code in several instances.
So, using variadic macros will break downward compatibility.
I'm not sure I understand what you are saying.
Well, perhaps I should have written: Variadic macros are covered by C99 or later only, not by C90. So, whereever you want to introduce them, you have to provide a parallel C90 implementation, unless you want to exclude all non C99 conformant compilers. IMHO, if you use variadic macros to optimize internal processing for a subset of compilers, this is ok. But you must not expose them on the outside interface of BOOST_PP (such as to declare a new type), because that wouldn't be portable. And I am not sure whether BOOST_PP_ARRAY already covers much of the preprocessor type you had in mind.
I wasn't suggesting to use variadic macros in BOOST_PP_TUPLE_*, I meant new macros _like_ BOOST_PP_TUPLE_*. there are only 6 or so TUPLE macros, and their predominant use is probably: converting a tuple to a sequence.
Side note: I noticed they are often used as a sort of preprocessor struct, where you have cheap random access to 'members'.
that would effectively introducde a new "data type" to the PP library: a variadic tuple.
I'm sure I'm not the first to suggest this, but with the workaround submitted to that microsoft site MSVC can be supported (along with all compilers implementing (conforming) C99 variadic macros)
If you think it is time to leave C90 behind, it might be worth
no I don't.
-- GMX DSL SOMMER-SPECIAL: Surf & Phone Flat 16.000 für nur 19,99 ¿/mtl.!* http://portal.gmx.net/de/go/dsl

Zitat von Wolf Lammen <ookami1@gmx.de>:
Well, perhaps I should have written: Variadic macros are covered by C99 or later only, not by C90. So, whereever you want to introduce them, you have to provide a parallel C90 implementation, unless you want to exclude all non C99 conformant compilers.
IMHO, if you use variadic macros to optimize internal processing for a subset of compilers, this is ok. But you must not expose them on the outside interface of BOOST_PP (such as to declare a new type), because that wouldn't be portable.
boost already does that in many cases, and there are many more to come due to c++0x. even type "long long" is C99/C++0x. that's what Boost.Config is for. this thread has been about adding a macro to indicate variadic macro support to Boost.Config, and then I brought up supporting variadic macros in Boost.Preprocessor through variadic tuples - for those compilers that support them (which probably includes MSVC thanks to the mentioned bug workaround). I don't see how this relates to specific PP engines like "chaos", or why variadic tuples could only be used internally, as long as it is documented that they require compiler support.

On 8/6/2010 5:11 AM, Wolf Lammen wrote:
someone there has submitted a workaround for this bug. I've tried it, it looks sufficient to implement macros like BOOST_PP_TUPLE_*, but variadic, without the "size" parameter for MSVC (and C99/C++0x)
Hi,
Variadic macros are part of the C99 standard. Judging from the preprocessor sources, their developers Mr Mensonides (and perhaps Mr Karvonen) seem to have painfully avoided breaking any rule of the C90 standard. For example, there are never empty macro arguments passed, although this would have simplified code in several instances.
So, using variadic macros will break downward compatibility.
If you think it is time to leave C90 behind, it might be worth evaluating one of the preprocessor engines Chaos (Mensonides) or Order (Karvonen) developed several years ago.
Cheers
Wolf Lammen
The only way to solve Edward's problem without relying on non-portable implementation artifacts is to use variadic macros. If you have variadics available, you can discriminate between streams of preprocessing tokens which begin with a left parenthesis (and contain a matching right parenthesis later) and streams of tokens which do not begin with a left parenthesis. AFAIK, given an arbitrary input stream (with the exception that unmatched parentheses are disallowed), there is no way to distinguish between the case where the parenthesized expression is the entire expression versus the the case where the parenthesized expression is only at the beginning of the expression. E.g. the difference between (a, b, c) and something like a C-style cast (int)abc. If you limit the input, you can do more. Specifically, given variadics and placeholders, you can detect and remove a leading parenthesized sequence of preprocessing tokens leaving a possibly empty sequence of preprocessing tokens, but you cannot construct a fully general-purpose macro that detects whether a sequence of preprocessing tokens is empty. The closest approximation to a such a macro is one that the input is not allowed to terminate with the name of a function-like macro. With stuff from chaos-pp: // test.cpp #include <chaos/preprocessor/control/inline_when.h> #include <chaos/preprocessor/detection/is_empty.h> #include <chaos/preprocessor/detection/is_variadic.h> #include <chaos/preprocessor/logical/bitand.h> #include <chaos/preprocessor/tuple/eat.h> #include <chaos/preprocessor/tuple/rem.h> #define TEST(...) \ CHAOS_PP_INLINE_WHEN( \ CHAOS_PP_BITAND \ (CHAOS_PP_IS_VARIADIC(__VA_ARGS__)) \ (CHAOS_PP_IS_EMPTY_NON_FUNCTION(CHAOS_PP_EAT __VA_ARGS__)) \ )(CHAOS_PP_REM) __VA_ARGS__ \ /**/ TEST(a, b, c) // a, b, c TEST((int)abc) // (int)abc TEST((a, x)) // a, x gcc -E -P -std=c++0x -I $CHAOS_ROOT -DCHAOS_PP_VARIADICS test.cpp If preprocessors were better, meaning that they actually closely approximated the standard(s), there are methods that can be used to deal with this that don't require variadics or any special handling within the macro. Unfortunately, doing such things requires much a much better preprocessor than the one in VC++ (which is a horrible piece of crap). E.g. // test.cpp #include <chaos/preprocessor/punctuation/comma.h> #include <chaos/preprocessor/punctuation/paren.h> #include <chaos/preprocessor/recursion/rail.h> #define M1(x) M2(x) #define M2(x) M3(x) #define M3(x) x #define L CHAOS_PP_UNSAFE_RAIL(CHAOS_PP_LPAREN)() #define R CHAOS_PP_UNSAFE_RAIL(CHAOS_PP_RPAREN)() #define C CHAOS_PP_UNSAFE_RAIL(CHAOS_PP_COMMA)() M1(123) // 123 CHAOS_PP_WALL( M1(C R L C) ) // , ) ( , gcc -E -P -std=c++0x -I $CHAOS_ROOT test.cpp Using similar stuff, chaos-pp already has some non-invasive facilities designed to pass around things like type names that come from templates with multiple arguments. #include <chaos/preprocessor/facilities/type.h> #include <chaos/preprocessor/recursion/rail.h> #define A(x) B(x) #define B(x) C(x) #define C(x) x CHAOS_PP_WALL(A( std::vector<CHAOS_PP_TYPE(std::pair<int, int>)> )) // std::vector<std::pair<int, int>> gcc -E -P -std=c++0x -I $CHAOS_ROOT -DCHAOS_PP_VARIADICS test.cpp In fact, the macros through which such things are passed need not be designed to handle them: // test.cpp #include <boost/preprocessor/punctuation/comma_if.hpp> #include <boost/preprocessor/seq/for_each_i.hpp> #include <chaos/preprocessor/facilities/type.h> #include <chaos/preprocessor/recursion/rail.h> #define MACRO(r, data, i, elem) BOOST_PP_COMMA_IF(i) elem #define TYPELIST(seq) \ CHAOS_PP_WALL( \ typelist< \ BOOST_PP_SEQ_FOR_EACH_I( \ MACRO, ~, seq \ ) \ > \ ) \ /**/ TYPELIST( (int) (double) (CHAOS_PP_TYPE(std::pair<int, int>)) (std::complex<double>) ) // typelist<int, double, std::pair<int, int>, std::complex<double> > gcc -E -P -std=c++0x -I $BOOST_ROOT -I $CHAOS_ROOT -DCHAOS_PP_VARIADICS test.cpp What's interesting to note in this case is that variadic content is being passed _through_ a library (the Boost pp-lib) that is not designed to handle variadic content _and_ being buried in the middle of arbitrary output. (Similar stuff can be done without variadics, but the encoding is much more verbose.) The basic problem with the Boost pp-lib is that it has to be portable--even to preprocessors that are foundationally broken (such as MSVC). Because of that, it really represents the lowest common denominator of what can be done with the preprocessor stably across so many targets. This is particularly true because the metaprogramming libraries in Boost are used heavily by other "regular" Boost libraries. In the case of VC++, some uses of variadics could be made to work with enough effort, but variadics themselves are not yet portable enough in C++ compilers to deploy as a required API in Boost. OTOH, there are preprocessors out there that can handle the far more advanced tricks that (e.g.) chaos-pp uses. GCC, EDG-based compilers, Wave, and a few others, for example, can all handle virtually all of chaos-pp. Regards, Paul Mensonides

On 8/7/2010 3:12 AM, Paul Mensonides wrote:
On 8/6/2010 5:11 AM, Wolf Lammen wrote:
someone there has submitted a workaround for this bug. I've tried it, it looks sufficient to implement macros like BOOST_PP_TUPLE_*, but variadic, without the "size" parameter for MSVC (and C99/C++0x)
Hi,
Variadic macros are part of the C99 standard. Judging from the preprocessor sources, their developers Mr Mensonides (and perhaps Mr Karvonen) seem to have painfully avoided breaking any rule of the C90 standard. For example, there are never empty macro arguments passed, although this would have simplified code in several instances.
So, using variadic macros will break downward compatibility.
If you think it is time to leave C90 behind, it might be worth evaluating one of the preprocessor engines Chaos (Mensonides) or Order (Karvonen) developed several years ago.
Cheers
Wolf Lammen
The only way to solve Edward's problem without relying on non-portable implementation artifacts is to use variadic macros. If you have variadics available, you can discriminate between streams of preprocessing tokens which begin with a left parenthesis (and contain a matching right parenthesis later) and streams of tokens which do not begin with a left parenthesis.
AFAIK, given an arbitrary input stream (with the exception that unmatched parentheses are disallowed), there is no way to distinguish between the case where the parenthesized expression is the entire expression versus the the case where the parenthesized expression is only at the beginning of the expression. E.g. the difference between (a, b, c) and something like a C-style cast (int)abc. If you limit the input, you can do more. Specifically, given variadics and placeholders, you can detect and remove a leading parenthesized sequence of preprocessing tokens leaving a possibly empty sequence of preprocessing tokens, but you cannot construct a fully general-purpose macro that detects whether a sequence of preprocessing tokens is empty. The closest approximation to a such a macro is one that the input is not allowed to terminate with the name of a function-like macro. With stuff from chaos-pp:
// test.cpp
#include <chaos/preprocessor/control/inline_when.h> #include <chaos/preprocessor/detection/is_empty.h> #include <chaos/preprocessor/detection/is_variadic.h> #include <chaos/preprocessor/logical/bitand.h> #include <chaos/preprocessor/tuple/eat.h> #include <chaos/preprocessor/tuple/rem.h>
#define TEST(...) \ CHAOS_PP_INLINE_WHEN( \ CHAOS_PP_BITAND \ (CHAOS_PP_IS_VARIADIC(__VA_ARGS__)) \ (CHAOS_PP_IS_EMPTY_NON_FUNCTION(CHAOS_PP_EAT __VA_ARGS__)) \ )(CHAOS_PP_REM) __VA_ARGS__ \ /**/
TEST(a, b, c) // a, b, c TEST((int)abc) // (int)abc TEST((a, x)) // a, x
gcc -E -P -std=c++0x -I $CHAOS_ROOT -DCHAOS_PP_VARIADICS test.cpp
If preprocessors were better, meaning that they actually closely approximated the standard(s), there are methods that can be used to deal with this that don't require variadics or any special handling within the macro. Unfortunately, doing such things requires much a much better preprocessor than the one in VC++ (which is a horrible piece of crap). E.g.
// test.cpp
#include <chaos/preprocessor/punctuation/comma.h> #include <chaos/preprocessor/punctuation/paren.h> #include <chaos/preprocessor/recursion/rail.h>
#define M1(x) M2(x) #define M2(x) M3(x) #define M3(x) x
#define L CHAOS_PP_UNSAFE_RAIL(CHAOS_PP_LPAREN)() #define R CHAOS_PP_UNSAFE_RAIL(CHAOS_PP_RPAREN)() #define C CHAOS_PP_UNSAFE_RAIL(CHAOS_PP_COMMA)()
M1(123) // 123
CHAOS_PP_WALL( M1(C R L C) ) // , ) ( ,
gcc -E -P -std=c++0x -I $CHAOS_ROOT test.cpp
Using similar stuff, chaos-pp already has some non-invasive facilities designed to pass around things like type names that come from templates with multiple arguments.
#include <chaos/preprocessor/facilities/type.h> #include <chaos/preprocessor/recursion/rail.h>
#define A(x) B(x) #define B(x) C(x) #define C(x) x
CHAOS_PP_WALL(A( std::vector<CHAOS_PP_TYPE(std::pair<int, int>)> )) // std::vector<std::pair<int, int>>
gcc -E -P -std=c++0x -I $CHAOS_ROOT -DCHAOS_PP_VARIADICS test.cpp
In fact, the macros through which such things are passed need not be designed to handle them:
// test.cpp
#include <boost/preprocessor/punctuation/comma_if.hpp> #include <boost/preprocessor/seq/for_each_i.hpp>
#include <chaos/preprocessor/facilities/type.h> #include <chaos/preprocessor/recursion/rail.h>
#define MACRO(r, data, i, elem) BOOST_PP_COMMA_IF(i) elem
#define TYPELIST(seq) \ CHAOS_PP_WALL( \ typelist< \ BOOST_PP_SEQ_FOR_EACH_I( \ MACRO, ~, seq \ ) \
\ ) \ /**/
TYPELIST( (int) (double) (CHAOS_PP_TYPE(std::pair<int, int>)) (std::complex<double>) ) // typelist<int, double, std::pair<int, int>, std::complex<double> >
gcc -E -P -std=c++0x -I $BOOST_ROOT -I $CHAOS_ROOT -DCHAOS_PP_VARIADICS test.cpp
What's interesting to note in this case is that variadic content is being passed _through_ a library (the Boost pp-lib) that is not designed to handle variadic content _and_ being buried in the middle of arbitrary output. (Similar stuff can be done without variadics, but the encoding is much more verbose.)
The basic problem with the Boost pp-lib is that it has to be portable--even to preprocessors that are foundationally broken (such as MSVC). Because of that, it really represents the lowest common denominator of what can be done with the preprocessor stably across so many targets. This is particularly true because the metaprogramming libraries in Boost are used heavily by other "regular" Boost libraries.
In the case of VC++, some uses of variadics could be made to work with enough effort, but variadics themselves are not yet portable enough in C++ compilers to deploy as a required API in Boost.
OTOH, there are preprocessors out there that can handle the far more advanced tricks that (e.g.) chaos-pp uses. GCC, EDG-based compilers, Wave, and a few others, for example, can all handle virtually all of chaos-pp.
If Boost had a configuration macro indicating which compilers support variadic macros, would this help the preprocessor library any in implementing functionality ? Or do you see implementing certain preprocessor functionality for only the subset of compilers that support variadic macros not worthwhile ?

On 8/7/2010 6:35 AM, Edward Diener wrote:
If Boost had a configuration macro indicating which compilers support variadic macros, would this help the preprocessor library any in implementing functionality ? Or do you see implementing certain preprocessor functionality for only the subset of compilers that support variadic macros not worthwhile ?
I wouldn't say "not worthwhile", but the variadic support would be minimal unless large chunks of the API are designed for it. What I noticed when writing Chaos is that to really get the benefits of variadics, you need to alter the a lot of stuff. Specifically, in how it relates to compatibility, you need to alter parameter orders all over the place since the set of variadic arguments are always the last. Regards, Paul Mensonides

On 8/7/2010 4:07 PM, Paul Mensonides wrote:
On 8/7/2010 6:35 AM, Edward Diener wrote:
If Boost had a configuration macro indicating which compilers support variadic macros, would this help the preprocessor library any in implementing functionality ? Or do you see implementing certain preprocessor functionality for only the subset of compilers that support variadic macros not worthwhile ?
I wouldn't say "not worthwhile", but the variadic support would be minimal unless large chunks of the API are designed for it. What I noticed when writing Chaos is that to really get the benefits of variadics, you need to alter the a lot of stuff. Specifically, in how it relates to compatibility, you need to alter parameter orders all over the place since the set of variadic arguments are always the last.
Regards, Paul Mensonides
That's totally understandable. Some time in the future, perhaps after the next version of C++ becomes official, all compilers will support variadic macros. Still I would like to see a Boost config macro which can be used to determine now if a particular compiler supports variadic macros.
participants (4)
-
Edward Diener
-
Paul Mensonides
-
Stefan Strasser
-
Wolf Lammen