[preprocessor] Warning: Incoming

I'm about to commit a relatively significant changeset to the pp-lib. This is the result of work by Edward Diener and I to add limited variadic support to the pp-lib. Edward can comment in more detail regarding the extent of those changes, but they do not add ground-up support. However, there are significant changes to heavily used low-level facilities such as BOOST_PP_TUPLE_ELEM (sometimes even complete implementation replacements). We have put in a great deal of effort to avoid introducing new errors or warnings in either the building of the Boost binaries or in the regression tests. However, we may have missed some issues. Regards, Paul Mensonides

On Sun, Jun 26, 2011 at 9:02 AM, Paul Mensonides <pmenso57@comcast.net> wrote:
I'm about to commit a relatively significant changeset to the pp-lib.
Do these changes need to be peer-reviewed?
This is the result of work by Edward Diener and I to add limited variadic support to the pp-lib. Edward can comment in more detail regarding the extent of those changes, but they do not add ground-up support.
If the pp-lib needs to be changed, why not change it radically to add ground-up variadic support? (This is not a rhetoric question. I am sincerely asking as there might be very good reasons not to add ground-up variadic support to Boost.Preprocessor.)
However, there are significant changes to heavily used low-level facilities such as BOOST_PP_TUPLE_ELEM (sometimes even complete implementation replacements). We have put in a great deal of effort to avoid introducing new errors or warnings in either the building of the Boost binaries or in the regression tests. However, we may have missed some issues.
I use Boost.Preprocessor (PP_TUPLE_, etc) pervasively in the implementation of a lot of macros in my projects. I also occasionally use Edward's VMD library. I will haply test the Boost.Preprocessor changes against my code. --Lorenzo

On 6/26/2011 10:57 AM, Lorenzo Caminiti wrote:
On Sun, Jun 26, 2011 at 9:02 AM, Paul Mensonides<pmenso57@comcast.net> wrote:
I'm about to commit a relatively significant changeset to the pp-lib.
Do these changes need to be peer-reviewed?
I will leave Paul to comment on this if he wishes.
This is the result of work by Edward Diener and I to add limited variadic support to the pp-lib. Edward can comment in more detail regarding the extent of those changes, but they do not add ground-up support.
If the pp-lib needs to be changed, why not change it radically to add ground-up variadic support? (This is not a rhetoric question. I am sincerely asking as there might be very good reasons not to add ground-up variadic support to Boost.Preprocessor.)
I am not sure what Paul meant by "ground-up" variadic support, nor how you take it, but the variadic support in pp-lib is very much the same as in my VMD library with a few added enhancements based on Paul's knowledge of preprocessor programming. The overall intent in pp-lib was the same as VMD: to integrate the use of variadic macros with pp-lib's richer data types ( tuple, array, list, seq ) and to enhance the use of pp-lib tuples with variadic macro support.
However, there are significant changes to heavily used low-level facilities such as BOOST_PP_TUPLE_ELEM (sometimes even complete implementation replacements). We have put in a great deal of effort to avoid introducing new errors or warnings in either the building of the Boost binaries or in the regression tests. However, we may have missed some issues.
I use Boost.Preprocessor (PP_TUPLE_, etc) pervasively in the implementation of a lot of macros in my projects. I also occasionally use Edward's VMD library. I will haply test the Boost.Preprocessor changes against my code.
That would be very welcome. I added a section in the pp-lib documentation under "Topics" called "variadic macros" which should help you.

On Sun, 26 Jun 2011 11:31:55 -0400, Edward Diener wrote:
On 6/26/2011 10:57 AM, Lorenzo Caminiti wrote:
If the pp-lib needs to be changed, why not change it radically to add ground-up variadic support? (This is not a rhetoric question. I am sincerely asking as there might be very good reasons not to add ground-up variadic support to Boost.Preprocessor.)
I am not sure what Paul meant by "ground-up" variadic support, nor how you take it, but the variadic support in pp-lib is very much the same as in my VMD library with a few added enhancements based on Paul's knowledge of preprocessor programming. The overall intent in pp-lib was the same as VMD: to integrate the use of variadic macros with pp-lib's richer data types ( tuple, array, list, seq ) and to enhance the use of pp-lib tuples with variadic macro support.
This is a good summary of the changes. What I meant by "ground-up" would be effectively re-implementing Boost.Preprocessor from scratch with variadic macros and placemarkers in mind. For example, with decent preprocessors (something we don't have as a rule), this would drastically reduce the number of use cases for BOOST_PP_TUPLE_ELEM. The use case I'm specifically thinking of at the moment is the encoding and decoding of auxiliary data or state data passed through algorithms provided by the library. E.g. #define ADD(x, y) WHILE(PRED, OP, (x, y)) #define PRED(d, state) \ TUPLE_ELEM(2, 1, state) \ /**/ #define OP(d, state) \ (INC(TUPLE_ELEM(2, 0, state)), DEC(TUPLE_ELEM(2, 1, state))) \ /**/ This one type of scenario decreases the efficiency and drastically decreases the readability of the code because the TUPLE_ELEM (or similar) clutter required in the implementation of both PRED and OP is either pervasive or results in more macro definitions. Ground-up support would imply that WHILE (and every other higher-order macro in the library) allow variadic state such that the example becomes: #define ADD(x, y) WHILE(PRED, OP, x, y) #define PRED(d, x, y) y #define OP(d, x, y) INC(x), DEC(y) The amount of clutter, even in this trivial example, is significantly reduced resulting in smaller, more efficient, and more readable code. However, even doing this requires breaking interfaces because existing arguments are in the wrong orders in many places. For example, SEQ_FOLD_LEFT's interface is SEQ_FOLD_LEFT(op, state, seq) where op's interface must be op(s, state, elem). This would need to be SEQ_FOLD_LEFT (op, (a1, a2, ...)(b1, b2, ...), s1, s2, ...) where op's interface must "compatible" with op(s, e1, e2, ..., s1, s2, ...). In this case, that's variadic accumulation state (i.e. fold state) together with potentially n- ary sequence data (in this case, not variadic sequence data such as (1) (1, 2)(1, 2, 3), but sequence data that is unary (1)(1)(1), binary (1, 2) (1, 2)(1, 2), or whatever so long as each element has the same "arity"). All of that aside, there is no way to generalize recursion on broken compilers--particularly popular ones such as VC++. The lack of this leads to an implementation explosion. Every reentrant algorithm in Boost.Preprocessor is implemented with a huge set of macros. Often times, they are implemented with multiple huge sets of macros which are different in that they contain differing workarounds for various compilers. Furthermore, many other higher-order algorithms are not reentrant because they are not implemented that way (and are instead implemented in terms of the ones which are). This inherently leads to implementation bubbling which is particularly costly with the preprocessor since there is no direct recursion and because the resulting error messages can be as bad as template-related error messages. With decent preprocessors, on the other hand, recursion is both generalizable and extensible. For example, all higher-order algorithms in Chaos are reentrant and none of them are implemented via huge sets of algorithm-specific macros. At the end of the day, the lack of generalizable recursion is even more fundamental and cripples Boost.Preprocessor even more than lack of ground-up support for variadic macros. I consider the entire methodology of Boost.Preprocessor to be garbage due to widespread, aspectual workarounds. Because of the above, I have no incentive to put major effort into minor improvements particularly when some vendor is too lazy to fix their preprocessor (which is a minor implementation in comparison to the underlying compiler and optimizer) or has too much of a "the standard is whatever we say it is" mentality. Regards, Paul Mensonides

Paul Mensonides wrote:
On Sun, 26 Jun 2011 11:31:55 -0400, Edward Diener wrote:
On 6/26/2011 10:57 AM, Lorenzo Caminiti wrote:
If the pp-lib needs to be changed, why not change it radically to add ground-up variadic support? (This is not a rhetoric question. I am sincerely asking as there might be very good reasons not to add ground-up variadic support to Boost.Preprocessor.)
I am not sure what Paul meant by "ground-up" variadic support, nor how you take it, but the variadic support in pp-lib is very much the same as in my VMD library with a few added enhancements based on Paul's knowledge of preprocessor programming. The overall intent in pp-lib was the same as VMD: to integrate the use of variadic macros with pp-lib's richer data types ( tuple, array, list, seq ) and to enhance the use of pp-lib tuples with variadic macro support.
This is a good summary of the changes.
What I meant by "ground-up" would be effectively re-implementing Boost.Preprocessor from scratch with variadic macros and placemarkers in mind. For example, with decent preprocessors (something we don't have as a rule), this would drastically reduce the number of use cases for BOOST_PP_TUPLE_ELEM. The use case I'm specifically thinking of at the moment is the encoding and decoding of auxiliary data or state data passed through algorithms provided by the library. E.g.
#define ADD(x, y) WHILE(PRED, OP, (x, y))
#define PRED(d, state) \ TUPLE_ELEM(2, 1, state) \ /**/ #define OP(d, state) \ (INC(TUPLE_ELEM(2, 0, state)), DEC(TUPLE_ELEM(2, 1, state))) \ /**/
This one type of scenario decreases the efficiency and drastically decreases the readability of the code because the TUPLE_ELEM (or similar) clutter required in the implementation of both PRED and OP is either pervasive or results in more macro definitions.
Ground-up support would imply that WHILE (and every other higher-order macro in the library) allow variadic state such that the example becomes:
#define ADD(x, y) WHILE(PRED, OP, x, y)
#define PRED(d, x, y) y #define OP(d, x, y) INC(x), DEC(y)
The amount of clutter, even in this trivial example, is significantly reduced resulting in smaller, more efficient, and more readable code.
However, even doing this requires breaking interfaces because existing arguments are in the wrong orders in many places. For example, SEQ_FOLD_LEFT's interface is SEQ_FOLD_LEFT(op, state, seq) where op's interface must be op(s, state, elem). This would need to be SEQ_FOLD_LEFT (op, (a1, a2, ...)(b1, b2, ...), s1, s2, ...) where op's interface must "compatible" with op(s, e1, e2, ..., s1, s2, ...). In this case, that's variadic accumulation state (i.e. fold state) together with potentially n- ary sequence data (in this case, not variadic sequence data such as (1) (1, 2)(1, 2, 3), but sequence data that is unary (1)(1)(1), binary (1, 2) (1, 2)(1, 2), or whatever so long as each element has the same "arity").
Yes, I remember we discussed this before when we first discussed the VMD library. As a user of Boost.Preprocessor, I agree 100% that spending the variadic argument on "data", "state", etc will incredibly simplify my pp code. However, even without that, variadic support similar to the one added by VMD is very useful. Therefore, I am looking forward to the Boost.Preprocessor variadic changes you have made (even if they don't provide "ground-up" variadic support and I'll have to continue to use PP_TUPLE_ELEM in the algorithms everywhere).
All of that aside, there is no way to generalize recursion on broken compilers--particularly popular ones such as VC++. The lack of this leads to an implementation explosion. Every reentrant algorithm in Boost.Preprocessor is implemented with a huge set of macros. Often times, they are implemented with multiple huge sets of macros which are different in that they contain differing workarounds for various compilers. Furthermore, many other higher-order algorithms are not reentrant because they are not implemented that way (and are instead implemented in terms of the ones which are). This inherently leads to implementation bubbling which is particularly costly with the preprocessor since there is no direct recursion and because the resulting error messages can be as bad as template-related error messages.
With decent preprocessors, on the other hand, recursion is both generalizable and extensible. For example, all higher-order algorithms in Chaos are reentrant and none of them are implemented via huge sets of algorithm-specific macros. At the end of the day, the lack of generalizable recursion is even more fundamental and cripples Boost.Preprocessor even more than lack of ground-up support for variadic macros. I consider the entire methodology of Boost.Preprocessor to be garbage due to widespread, aspectual workarounds. Because of the above, I have no incentive to put major effort into minor improvements particularly when some vendor is too lazy to fix their preprocessor (which is a minor implementation in comparison to the underlying compiler and optimizer) or has too much of a "the standard is whatever we say it is" mentality.
I understand that MVSC pp is broken and I share the pain of writing endless workarounds for that pp (especially to ensure proper macro expansions). I have take a good look look to Boost.Preprocessor implementation and I understand well the amount of work that went in it to support broken pp... At the end of the day, I need my code to also compile on MVSC so I'm "stock" with it whether a I like it or not :( Thanks a lot! --Lorenzo -- View this message in context: http://boost.2283326.n4.nabble.com/preprocessor-Warning-Incoming-tp3625881p3... Sent from the Boost - Dev mailing list archive at Nabble.com.

On Sun, 26 Jun 2011 10:57:55 -0400, Lorenzo Caminiti wrote:
On Sun, Jun 26, 2011 at 9:02 AM, Paul Mensonides <pmenso57@comcast.net> wrote:
I'm about to commit a relatively significant changeset to the pp-lib.
Do these changes need to be peer-reviewed?
No, but feel free to comment.
This is the result of work by Edward Diener and I to add limited variadic support to the pp-lib. Edward can comment in more detail regarding the extent of those changes, but they do not add ground-up support.
If the pp-lib needs to be changed, why not change it radically to add ground-up variadic support? (This is not a rhetoric question. I am sincerely asking as there might be very good reasons not to add ground-up variadic support to Boost.Preprocessor.)
The biggest reason not to do so would be compatibility. A ground-up reimplementation would entail significant interface breaking. A secondary reason is that there is a limit on what can be done while having to support broken preprocessors, and that limit has the potential to drastically undermine the benefits of doing so. To be clear, I'm not referring to having some support disabled for broken preprocessors. Rather, it would be having entirely different interfaces--just like Chaos has entirely different interfaces, and, more importantly, an entirely different methodology. That aside, if broken preprocessors are taken off the table (i.e. abandoning VC++ as a supported compiler or using a different preprocessor front-end to it such as Wave), there is already a library (Chaos) that was written from the ground up to support variadics that is released under the same license that Boost uses (and created). As an example, everything that Edward and I have added to Boost.Preprocessor has already existed in Chaos (in some form) for years. Regards, Paul Mensonides

On Mon, Jun 27, 2011 at 1:13 AM, Paul Mensonides <pmenso57@comcast.net> wrote:
That aside, if broken preprocessors are taken off the table (i.e. abandoning VC++ as a supported compiler or using a different
Is this true for all versions? If so, is there a MS connect issue we could vote on for a better preprocessor? Olaf

On 06/27/2011 11:48 AM, Olaf van der Spek wrote:
On Mon, Jun 27, 2011 at 1:13 AM, Paul Mensonides<pmenso57@comcast.net> wrote:
That aside, if broken preprocessors are taken off the table (i.e. abandoning VC++ as a supported compiler or using a different
Is this true for all versions?
Yes. Its variadic macro support is completely broken, but interestingly enough it is still possible to do a few things with it if you're willing to put MSVC-specific hacks everywhere.
If so, is there a MS connect issue we could vote on for a better preprocessor?
The main bug appears to be present three times in the database, twice as won't fix, and one that appeared just last month. http://connect.microsoft.com/VisualStudio/feedback/details/380090/variadic-m... http://connect.microsoft.com/VisualStudio/feedback/details/521844/variadic-m... http://connect.microsoft.com/VisualStudio/feedback/details/676585/bug-in-cl-...

On Mon, 27 Jun 2011 12:21:28 +0200, Mathias Gaunard wrote:
On 06/27/2011 11:48 AM, Olaf van der Spek wrote:
On Mon, Jun 27, 2011 at 1:13 AM, Paul Mensonides<pmenso57@comcast.net> wrote:
That aside, if broken preprocessors are taken off the table (i.e. abandoning VC++ as a supported compiler or using a different
Is this true for all versions?
Yes.
Its variadic macro support is completely broken, but interestingly enough it is still possible to do a few things with it if you're willing to put MSVC-specific hacks everywhere.
It's far deeper than that. Their entire macro replacement mechanism is fundamentally broken. However, MS's consistent response has been "won't fix." My response to that is "won't support." Regards, Paul Mensonides

On 6/27/2011 6:21 AM, Mathias Gaunard wrote:
On 06/27/2011 11:48 AM, Olaf van der Spek wrote:
On Mon, Jun 27, 2011 at 1:13 AM, Paul Mensonides<pmenso57@comcast.net> wrote:
That aside, if broken preprocessors are taken off the table (i.e. abandoning VC++ as a supported compiler or using a different
Is this true for all versions?
Yes.
Its variadic macro support is completely broken, but interestingly enough it is still possible to do a few things with it if you're willing to put MSVC-specific hacks everywhere.
Paul has gone out of his way to support the VC++ preprocessor in pp-lib, even though it is broken in many respects, with many hacks. I also had to find a hack to get VC++ to work with variadic macros in my VMD library, and the work I did with Paul to get variadic macros into pp-lib also needed various hacks for VC++. I write this because I want to emphasize that the updated pp-lib with variadic macro support does work with VC++, despite it being difficult to force the VC++ preprocessor to expand both variadic and non-variadic macros in a timely and correct manner in quite a number of cases. So while I share Paul's frustration at working with the VC++ preprocessor, and Microsoft's unwillingness to ever fix it ( they are probably afraid that actually fixing their preprocessor will break end-user's code which inadvertently relies on their buggy code ), I pushed very hard to have the functionality from my VMD library added to pp-lib and still support VC++. At the same time I totally understand that to write a really great preprocessor library, as Paul has done with Chaos, one needs to abandon support for broken preprocessors such as VC++ and work only with preprocessor which implement the C++ standard.

[Mathias Gaunard]
The main bug appears to be present three times in the database, twice as won't fix, and one that appeared just last month. http://connect.microsoft.com/VisualStudio/feedback/details/380090/variadic-m... http://connect.microsoft.com/VisualStudio/feedback/details/521844/variadic-m... http://connect.microsoft.com/VisualStudio/feedback/details/676585/bug-in-cl-...
I've passed these comments to our compiler front-end team, and they're going to take another look at fixing these bugs. They can't promise anything, but they'll try. Thanks, Stephan T. Lavavej Visual C++ Libraries Developer

On Sun, Jun 26, 2011 at 10:57 AM, Lorenzo Caminiti <lorcaminiti@gmail.com> wrote:
I use Boost.Preprocessor (PP_TUPLE_, etc) pervasively in the implementation of a lot of macros in my projects. I also occasionally use Edward's VMD library. I will haply test the Boost.Preprocessor changes against my code.
I've been using Boost.Preprocessor variadics in Boost.ScopeExit, Boost.Closure, and Boost.Contract. I have not seen any issue so far. I have a couple of comments: 1) Are the PP_VARIADIC macros documented? 2) There are some macros like PP_REM and PP_EAT that are defined inside tuple/... even if they do not have the PP_TUPLE_ prefix. They are also not documented. Are these part of the public API? If find these macros useful, I'd move them in facilities/ and document them... (BTW, BOOST_PP_IS_EMPTY is not documented either.) Thanks. --Lorenzo

On 1/14/2012 5:53 AM, Lorenzo Caminiti wrote:
On Sun, Jun 26, 2011 at 10:57 AM, Lorenzo Caminiti <lorcaminiti@gmail.com> wrote:
I use Boost.Preprocessor (PP_TUPLE_, etc) pervasively in the implementation of a lot of macros in my projects. I also occasionally use Edward's VMD library. I will haply test the Boost.Preprocessor changes against my code.
I've been using Boost.Preprocessor variadics in Boost.ScopeExit, Boost.Closure, and Boost.Contract. I have not seen any issue so far.
I have a couple of comments:
I am replying about what is on the trunk. I have tried to get Paul Mensonides to move the trunk code to release, but he seems to be busy and has not been able to do so as yet. I am responsible for the documentation for the variadic macro support on the trunk.
1) Are the PP_VARIADIC macros documented?
Yes. Look under the variadic header in the docs and in the reference starting with VARIADIC_.
2) There are some macros like PP_REM and PP_EAT that are defined inside tuple/... even if they do not have the PP_TUPLE_ prefix. They are also not documented. Are these part of the public API? If find these macros useful, I'd move them in facilities/ and document them... (BTW, BOOST_PP_IS_EMPTY is not documented either.)
I am for documenting BOOST_PP_IS_EMPTY, and for providing a better version based almost completely on Paul's improvement using variadic macros. He may feel different. As far as the internal PP_REM and PP_EAT Paul did not want them to be documented as yet. Hopefully he will respond with his further plans about them if any.

On Sat, 14 Jan 2012 08:40:31 -0500, Edward Diener wrote:
I have a couple of comments:
I am replying about what is on the trunk. I have tried to get Paul Mensonides to move the trunk code to release, but he seems to be busy and has not been able to do so as yet. I am responsible for the documentation for the variadic macro support on the trunk.
I merged it quite a while back now unless I merged it to the wrong place.
1) Are the PP_VARIADIC macros documented?
Yes. Look under the variadic header in the docs and in the reference starting with VARIADIC_.
2) There are some macros like PP_REM and PP_EAT that are defined inside tuple/... even if they do not have the PP_TUPLE_ prefix. They are also not documented. Are these part of the public API? If find these macros useful, I'd move them in facilities/ and document them... (BTW, BOOST_PP_IS_EMPTY is not documented either.)
I am for documenting BOOST_PP_IS_EMPTY, and for providing a better version based almost completely on Paul's improvement using variadic macros. He may feel different.
As far as the internal PP_REM and PP_EAT Paul did not want them to be documented as yet. Hopefully he will respond with his further plans about them if any.
The reason REM and EAT are not documented is because they lead to the same extreme sorts of workarounds in client code as are required in the pp-lib itself. Regards, Paul Mensonides

On 06/26/2011 03:02 PM, Paul Mensonides wrote:
I'm about to commit a relatively significant changeset to the pp-lib. This is the result of work by Edward Diener and I to add limited variadic support to the pp-lib. Edward can comment in more detail regarding the extent of those changes, but they do not add ground-up support.
What are the new features? Is it only new functions or are there also some fixes like allowing (a)(b, c)(d) to be a valid sequence?

On 6/27/2011 9:16 AM, Mathias Gaunard wrote:
On 06/26/2011 03:02 PM, Paul Mensonides wrote:
I'm about to commit a relatively significant changeset to the pp-lib. This is the result of work by Edward Diener and I to add limited variadic support to the pp-lib. Edward can comment in more detail regarding the extent of those changes, but they do not add ground-up support.
What are the new features? Is it only new functions or are there also some fixes like allowing (a)(b, c)(d) to be a valid sequence?
The new features are adding variadic macro support. No other fixes are provided. Look at 'variadic macros' under the Topics heading for what has been done. I believe I give a pretty good general explanation there. Of couurse the individual variadic macro support is documented under the Reference and Headers.

On 06/27/2011 04:01 PM, Edward Diener wrote:
On 6/27/2011 9:16 AM, Mathias Gaunard wrote:
On 06/26/2011 03:02 PM, Paul Mensonides wrote:
I'm about to commit a relatively significant changeset to the pp-lib. This is the result of work by Edward Diener and I to add limited variadic support to the pp-lib. Edward can comment in more detail regarding the extent of those changes, but they do not add ground-up support.
What are the new features? Is it only new functions or are there also some fixes like allowing (a)(b, c)(d) to be a valid sequence?
The new features are adding variadic macro support. No other fixes are provided. Look at 'variadic macros' under the Topics heading for what has been done. I believe I give a pretty good general explanation there. Of couurse the individual variadic macro support is documented under the Reference and Headers.
Ok, so there are a few new tuple "overloads" and a new "variadic" type which is essentially a tuple without the parentheses. May I suggest the addition of a macro that strips parentheses but only if they are present? I have found this to be very useful for passing arguments that contain commas easily.

On 6/27/2011 12:29 PM, Mathias Gaunard wrote:
On 06/27/2011 04:01 PM, Edward Diener wrote:
On 6/27/2011 9:16 AM, Mathias Gaunard wrote:
On 06/26/2011 03:02 PM, Paul Mensonides wrote:
I'm about to commit a relatively significant changeset to the pp-lib. This is the result of work by Edward Diener and I to add limited variadic support to the pp-lib. Edward can comment in more detail regarding the extent of those changes, but they do not add ground-up support.
What are the new features? Is it only new functions or are there also some fixes like allowing (a)(b, c)(d) to be a valid sequence?
The new features are adding variadic macro support. No other fixes are provided. Look at 'variadic macros' under the Topics heading for what has been done. I believe I give a pretty good general explanation there. Of couurse the individual variadic macro support is documented under the Reference and Headers.
Ok, so there are a few new tuple "overloads" and a new "variadic" type which is essentially a tuple without the parentheses.
May I suggest the addition of a macro that strips parentheses but only if they are present?
I do not think this is possible. But I am out of the loop regarding pp-lib additions and Paul would really know if this could be done.
I have found this to be very useful for passing arguments that contain commas easily.
Can you give an example of what you are trying to do ?

On 06/27/2011 10:37 PM, Edward Diener wrote:
May I suggest the addition of a macro that strips parentheses but only if they are present?
I do not think this is possible. But I am out of the loop regarding pp-lib additions and Paul would really know if this could be done.
Code to do this was already given on the Boost ML by Steven Watanabe: <http://article.gmane.org/gmane.comp.lib.boost.user/61011> I've already been using this for a year in my code, and it works fine. There is one little caveat with the above code, it's not strictly conforming to C99/C++0x so it doesn't work with Wave. Replacing (__VA_ARGS__, 2, 1) by (__VA_ARGS__, 2, 1, 0) fixes the problem.
I have found this to be very useful for passing arguments that contain commas easily.
Can you give an example of what you are trying to do ?
Consider something like BOOST_FOREACH(std::pair<A, B> a, mymap) this fails because the preprocessor sees it as three arguments. Assuming BOOST_FOREACH was using STRIP_PARENS on its arguments, you could do BOOST_FOREACH((std::pair<A, B> a), mymap) in the cases where it is necessary. This is actually pretty much a requirement when you want to write macros that take template with multiple parameters as arguments.

On 6/27/2011 5:25 PM, Mathias Gaunard wrote:
On 06/27/2011 10:37 PM, Edward Diener wrote:
May I suggest the addition of a macro that strips parentheses but only if they are present?
I do not think this is possible. But I am out of the loop regarding pp-lib additions and Paul would really know if this could be done.
Code to do this was already given on the Boost ML by Steven Watanabe: <http://article.gmane.org/gmane.comp.lib.boost.user/61011>
You are right and Steve came up with his technique in answering my own question.
I've already been using this for a year in my code, and it works fine.
There is one little caveat with the above code, it's not strictly conforming to C99/C++0x so it doesn't work with Wave. Replacing (__VA_ARGS__, 2, 1) by (__VA_ARGS__, 2, 1, 0)
fixes the problem.
I have found this to be very useful for passing arguments that contain commas easily.
Can you give an example of what you are trying to do ?
Consider something like
BOOST_FOREACH(std::pair<A, B> a, mymap)
this fails because the preprocessor sees it as three arguments.
Assuming BOOST_FOREACH was using STRIP_PARENS on its arguments, you could do
BOOST_FOREACH((std::pair<A, B> a), mymap)
in the cases where it is necessary.
This is actually pretty much a requirement when you want to write macros that take template with multiple parameters as arguments.
Tt is a good example. This has led me to work on some macros for pp-lib, which uses variadics, which can tell whether a macro parameter is a tuple, array, seq, or list. Then in your case you can go: #define STRIP_PARENS(x)\ BOOST_PP_IIF(BOOSTPP_IS_TUPLE(x),BOOST_PP_TUPLE_ENUM(x),x)

On Mon, Jun 27, 2011 at 4:21 PM, Edward Diener <eldiener@tropicsoft.com>wrote: [...]
This has led me to work on some macros for pp-lib, which uses variadics, which can tell whether a macro parameter is a tuple, array, seq, or list.
Then in your case you can go:
#define STRIP_PARENS(x)\ BOOST_PP_IIF(BOOSTPP_IS_TUPLE(x),BOOST_PP_TUPLE_ENUM(x),x)
I'm not a preprocessing expert, so I would be afraid of the preprocessor trying to expand BOOST_PP_TUPLE_ENUM(x) when x is not a tuple. If so, I would think something like #define STRIP_PARENS( x ) BOOST_PP_IIF( BOOST_PP_IS_TUPLE( x ), BOOST_PP_TUPLE_ENUM, BOOST_PP_IDENTITY ) ( x ) would be better...? - Jeff

On 6/27/2011 8:31 PM, Jeffrey Lee Hellrung, Jr. wrote:
On Mon, Jun 27, 2011 at 4:21 PM, Edward Diener<eldiener@tropicsoft.com>wrote: [...]
This has led me to work on some macros for pp-lib, which uses variadics, which can tell whether a macro parameter is a tuple, array, seq, or list.
Then in your case you can go:
#define STRIP_PARENS(x)\ BOOST_PP_IIF(BOOSTPP_IS_TUPLE(x),BOOST_PP_TUPLE_ENUM(x),x)
I'm not a preprocessing expert, so I would be afraid of the preprocessor trying to expand BOOST_PP_TUPLE_ENUM(x) when x is not a tuple. If so, I would think something like
#define STRIP_PARENS( x ) BOOST_PP_IIF( BOOST_PP_IS_TUPLE( x ), BOOST_PP_TUPLE_ENUM, BOOST_PP_IDENTITY ) ( x )
would be better...?
You are right. Good catch !

On Mon, 27 Jun 2011 23:25:15 +0200, Mathias Gaunard wrote:
Consider something like
BOOST_FOREACH(std::pair<A, B> a, mymap)
this fails because the preprocessor sees it as three arguments.
Assuming BOOST_FOREACH was using STRIP_PARENS on its arguments, you could do
Chaos has a macro that does this called CHAOS_PP_DECODE (and a corresponding CHAOS_PP_ENCODE which is provided for symmetry). However, assuming BOOST_FOREACH doesn't use it, you can still do it... // 1.cpp #include <boost/foreach.hpp> #include <chaos/preprocessor/facilities/type.h> #include <chaos/preprocessor/recursion/rail.h> CHAOS_PP_WALL( BOOST_FOREACH( CHAOS_PP_TYPE(std::pair<A, B> a), mymap ) ) { /* ... */ } g++ -E -P -std=gnu++0x -I $BOOST_ROOT -I $CHAOS_ROOT -D CHAOS_PP_VARIADICS 1.cpp ...or, cleaned up... // 2.cpp #include <boost/foreach.hpp> #include <chaos/preprocessor/facilities/encode.h> #include <chaos/preprocessor/facilities/type.h> #include <chaos/preprocessor/recursion/rail.h> #define FOREACH(d, c) \ CHAOS_PP_WALL(BOOST_FOREACH( \ CHAOS_PP_TYPE(CHAOS_PP_DECODE(d)), \ c \ )) \ /**/ FOREACH((std::pair<A, B> a), mymap) { /* ... */ } g++ -E -P -std=gnu++0x -I $BOOST_ROOT -I $CHAOS_ROOT -D CHAOS_PP_VARIADICS 2.cpp How's that for black magic? Chaos calls this sort of thing a "rail" (in the railgun sense) because it sends nearly arbitrary stuff through any amount of macro machinery and expands it (and any number of copies of it) after it comes out the other side regardless of where it appears in the output. Regards, Paul Mensonides

On 6/27/2011 5:25 PM, Mathias Gaunard wrote:
On 06/27/2011 10:37 PM, Edward Diener wrote:
May I suggest the addition of a macro that strips parentheses but only if they are present?
I do not think this is possible. But I am out of the loop regarding pp-lib additions and Paul would really know if this could be done.
Code to do this was already given on the Boost ML by Steven Watanabe: <http://article.gmane.org/gmane.comp.lib.boost.user/61011>
I've already been using this for a year in my code, and it works fine.
There is one little caveat with the above code, it's not strictly conforming to C99/C++0x so it doesn't work with Wave. Replacing (__VA_ARGS__, 2, 1) by (__VA_ARGS__, 2, 1, 0)
fixes the problem.
I have found this to be very useful for passing arguments that contain commas easily.
Can you give an example of what you are trying to do ?
Consider something like
BOOST_FOREACH(std::pair<A, B> a, mymap)
this fails because the preprocessor sees it as three arguments.
Assuming BOOST_FOREACH was using STRIP_PARENS on its arguments, you could do
BOOST_FOREACH((std::pair<A, B> a), mymap)
in the cases where it is necessary.
This is actually pretty much a requirement when you want to write macros that take template with multiple parameters as arguments.
As a side note, since STRIP_PARENS needs variadic macros anyway, BOOST_FOREACH could take its arguments as variadic data without needing the end-user to put parens around its first argument when an embedded comma is present. Of course this would need for Eric Niebler to change BOOST_FOREACH to support variadics when present. Nonetheless macros using variadics to identify pp-lib data types on the fly might still be useful and I have already come up with a pretty good IS_TUPLE. Whether an IS_ARRAY, IS_LIST, or IS_SEQ is posible I shall see. I will probably end up putting any additions in my VMD library for the time being and if Paul decides that he wants them for pp-lib sometime in the future they will eventually go there.

On Wed, Jun 29, 2011 at 10:54 AM, Edward Diener <eldiener@tropicsoft.com> wrote:
Nonetheless macros using variadics to identify pp-lib data types on the fly might still be useful and I have already come up with a pretty good IS_TUPLE. Whether an IS_ARRAY, IS_LIST, or IS_SEQ is posible I shall see.
Useful indeed. I have implemented some sort of IS_TUPLE within Boost.Local. BOOST_LOCAL_PARAMS() uses it to accept both the follow syntaxes when variadics are present: BOOST_LOCAL_PARAMS(int x, int& y) // (1) BOOST_LOCAL_PARAMS( (int x) (int& y) ) // (2) Essentially (going by memory): #if BOOST_VARIADICS_MACRO #define BOOST_LOCAL_PARAMS(...) \ BOOST_PP_IIF(IS_TUPLE(__VA_ARGS__), \ BOOST_LOCAL_PARAMS_TUPLE_ /* for (1) */ \ , \ BOOST_LOCAL_PARAMS_SEQ_ /* for (2) */ \ )(__VA_ARGS__) #else // variadics #define BOOST_LOCAL_PARAMS(seq) BOOST_LOCAL_PARAMS_SEQ_(seq) // only (2) :( #endif // variadics
I will probably end up putting any additions in my VMD library for the time being and if Paul decides that he wants them for pp-lib sometime in the future they will eventually go there.
I'd prefer to see IS_TUPLE (and possibly all IS_XXX) as part of these Boost.Preprocess variadics changes. --Lorenzo

On 6/30/2011 9:31 PM, Lorenzo Caminiti wrote:
On Wed, Jun 29, 2011 at 10:54 AM, Edward Diener<eldiener@tropicsoft.com> wrote:
Nonetheless macros using variadics to identify pp-lib data types on the fly might still be useful and I have already come up with a pretty good IS_TUPLE. Whether an IS_ARRAY, IS_LIST, or IS_SEQ is posible I shall see.
Useful indeed. I have implemented some sort of IS_TUPLE within Boost.Local.
It is certainly possible to do an IS_TUPLE when the possibilities are confined but it is not possible to do an IS_TUPLE which works in every case due to having to use IS_EMPTY to check that there is nothing beyond the end paren. If you think you have a fail-safe implementation if IS_TUPLE, feel free to share it. I will post an IS_TUPLE in my VMD library, with a note about the possible problem which could occur, but since I have my TTI library upcoming for review, I will wait until that review is ended. It is not possible to do an IS_ARRAY or an IS_LIST because it is not possible to check for a number or the presence of BOOST_PP_NIL. Using the well known concatenation technique to check for a particular token fails when the token tested can not be legally concatenated, ie. BOOST_PP_IS_1(+) fails with a programming error. It is possible to do an IS_SEQ based on IS_TUPLE, but with the same limitation IS_TUPLE has. I will post an IS_SEQ in my VMD library eventually also.
BOOST_LOCAL_PARAMS() uses it to accept both the follow syntaxes when variadics are present:
BOOST_LOCAL_PARAMS(int x, int& y) // (1) BOOST_LOCAL_PARAMS( (int x) (int& y) ) // (2)
Essentially (going by memory):
#if BOOST_VARIADICS_MACRO
#define BOOST_LOCAL_PARAMS(...) \ BOOST_PP_IIF(IS_TUPLE(__VA_ARGS__), \ BOOST_LOCAL_PARAMS_TUPLE_ /* for (1) */ \ , \ BOOST_LOCAL_PARAMS_SEQ_ /* for (2) */ \ )(__VA_ARGS__)
#else // variadics
#define BOOST_LOCAL_PARAMS(seq) BOOST_LOCAL_PARAMS_SEQ_(seq) // only (2) :(
#endif // variadics
I will probably end up putting any additions in my VMD library for the time being and if Paul decides that he wants them for pp-lib sometime in the future they will eventually go there.
I'd prefer to see IS_TUPLE (and possibly all IS_XXX) as part of these Boost.Preprocess variadics changes.
I do not control what Paul decides to add to pp-lib, but I am discussing these possibilities with him and he can decide the end result.

On Thu, 30 Jun 2011 21:31:22 -0400, Lorenzo Caminiti wrote:
On Wed, Jun 29, 2011 at 10:54 AM, Edward Diener <eldiener@tropicsoft.com> wrote:
Nonetheless macros using variadics to identify pp-lib data types on the fly might still be useful and I have already come up with a pretty good IS_TUPLE. Whether an IS_ARRAY, IS_LIST, or IS_SEQ is posible I shall see.
Useful indeed. I have implemented some sort of IS_TUPLE within Boost.Local. BOOST_LOCAL_PARAMS() uses it to accept both the follow syntaxes when variadics are present:
BOOST_LOCAL_PARAMS(int x, int& y) // (1) BOOST_LOCAL_PARAMS( (int x) (int& y) ) // (2)
One of the things that Edward and I are discussing is introducing an IS_VARIADIC macro along the lines of the other detection macros that already exist (i.e. IS_NULLARY, IS_UNARY, IS_BINARY). In essence, IS_VARIADIC detects whether its argument *begins* with a parenthesized expression (of any arity). However, it doesn't suffer the problems associated with try to detect emptiness. For example: IS_VARIADIC( int x, int& y ) // 0 IS_VARIADIC( (int x)(int& y) ) // 1 IS_VARIADIC( (...) xyz ) // 1 For your particular case, wouldn't that be sufficient? Regardless, I actually believe that the (1) case above is actually a large step *backwards*. It's worse, not better, because it's trying (and failing) to be the underlying language and introducing a bunch of gotchas in the attempt. For better variadic support, what's needed most are a few low-level macros such as IS_VARIADIC (small change) and a variadic/placemarker sequence implementation (large, though possibly not difficult, change). This notion of a, b, c being a good way to store elements (which are possibly empty sequences of preprocessing tokens and whitespace separations) needs to die. I was just watching some of the Boostcon videos and in one of them (something like Haskell = C++ TMP) there are examples that utilize variadic templates to pass around lists of types. However, in the example, they are "open". I.e. not bounded by something that collects them as a singular entity. I don't have it in front of me, but something like: template<class, class... T> struct count { enum { value = 1 + count<T...>::value }; }; template<> struct count<> { enum { value = 0 }; }; ...but this is terrible. It doesn't take away from the point of the talk, but it should be something like count<typelist<A, B, C>>, not count<A, B, C>. The same thing is true for these variadic macros.
I'd prefer to see IS_TUPLE (and possibly all IS_XXX) as part of these Boost.Preprocess variadics changes.
Not possible unless they are laden with (unreasonable) input constraints. Regards, Paul Mensonides

On Fri, Jul 1, 2011 at 2:09 AM, Paul Mensonides <pmenso57@comcast.net> wrote:
On Thu, 30 Jun 2011 21:31:22 -0400, Lorenzo Caminiti wrote:
On Wed, Jun 29, 2011 at 10:54 AM, Edward Diener <eldiener@tropicsoft.com> wrote:
Nonetheless macros using variadics to identify pp-lib data types on the fly might still be useful and I have already come up with a pretty good IS_TUPLE. Whether an IS_ARRAY, IS_LIST, or IS_SEQ is posible I shall see.
Useful indeed. I have implemented some sort of IS_TUPLE within Boost.Local. BOOST_LOCAL_PARAMS() uses it to accept both the follow syntaxes when variadics are present:
BOOST_LOCAL_PARAMS(int x, int& y) // (1) BOOST_LOCAL_PARAMS( (int x) (int& y) ) // (2)
One of the things that Edward and I are discussing is introducing an IS_VARIADIC macro along the lines of the other detection macros that already exist (i.e. IS_NULLARY, IS_UNARY, IS_BINARY). In essence, IS_VARIADIC detects whether its argument *begins* with a parenthesized expression (of any arity). However, it doesn't suffer the problems associated with try to detect emptiness. For example:
IS_VARIADIC( int x, int& y ) // 0 IS_VARIADIC( (int x)(int& y) ) // 1 IS_VARIADIC( (...) xyz ) // 1
For your particular case, wouldn't that be sufficient?
Yes, in fact IS_VARIADIC is the macro Boost.Local currently uses. See my rudimentary implementation at: http://svn.boost.org/svn/boost/sandbox/local/boost/local/aux_/preprocessor/v... This implementation is fine for Boost.Local but I have not tested in general and it might impose unacceptable limitation (like the empty issue we discussed also while discussing VMD).
Regardless, I actually believe that the (1) case above is actually a large step *backwards*. It's worse, not better, because it's trying (and failing) to be the underlying language and introducing a bunch of gotchas in the attempt.
I can only say that (i) I agree with you BUT (ii) my library users (my customers) wanted (1) very badly so I really have no choice.
I'd prefer to see IS_TUPLE (and possibly all IS_XXX) as part of these Boost.Preprocess variadics changes.
Not possible unless they are laden with (unreasonable) input constraints.
Yes, I agree that a Boost.Preprocessor version of IS_TUPLE (and also IS_VARIADIC) should work in general and not requiring input constraints. I did not play with Boost.Local IS_TUPLE/IS_VARIADIC enough to assess if it is possible or not but if you guys say that a generic IS_TUPLE is not possible that is of course a good reason not to add it to Boost.Preprocessor. --Lorenzo

On Fri, 01 Jul 2011 10:40:37 -0400, Lorenzo Caminiti wrote:
On Fri, Jul 1, 2011 at 2:09 AM, Paul Mensonides <pmenso57@comcast.net> wrote:
IS_VARIADIC( int x, int& y ) // 0 IS_VARIADIC( (int x)(int& y) ) // 1 IS_VARIADIC( (...) xyz ) // 1
For your particular case, wouldn't that be sufficient?
Yes, in fact IS_VARIADIC is the macro Boost.Local currently uses. See my rudimentary implementation at: http://svn.boost.org/svn/boost/sandbox/local/boost/local/aux_/ preprocessor/variadic/is.hpp
This implementation is fine for Boost.Local but I have not tested in general and it might impose unacceptable limitation (like the empty issue we discussed also while discussing VMD).
IS_VARIADIC can be defined without the issues associated with IS_EMPTY. The problem with the mythical IS_TUPLE is that it requires both IS_VARIADIC *and* IS_EMPTY and that is where the problems come in.
Regardless, I actually believe that the (1) case above is actually a large step *backwards*. It's worse, not better, because it's trying (and failing) to be the underlying language and introducing a bunch of gotchas in the attempt.
I can only say that (i) I agree with you BUT (ii) my library users (my customers) wanted (1) very badly so I really have no choice.
I know that in your particular case, it is already too late given that it is a deployed interface. However, the better strategy would be to let the third party make the (mistake of creating the) mapping. Those responsible for writing code should do it the right way as far as can be known at the time. For a library author, that means *not* providing poor interfaces. For a library, this is where the responsibility stops, and clients can do whatever they want--good or bad. They *should* understand the issues that result from what they do and do accordingly, but that is still up to them. In the case of the pp-lib, I'm the primary author and maintainer. Obviously, it's an open-source, multi-developer project, so others can make changes, but I will certainly push back against adding interfaces to the library which I believe to be bad interfaces. For the three interfaces in question: 0) IS_NULLARY, IS_UNARY, IS_BINARY, ... = good interfaces (< C99 || < C+ +0x) 1) IS_VARIADIC = good interface (>= C99 || >= C++0x) 2) IS_EMPTY = good interface only in a particular domain of applicability 3) IS_TUPLE = bad interface The IS_TUPLE scenario, even if it wasn't for the serious input constraints required by any IS_EMPTY implementation, is fundamentally broken in the larger context. IS_ARRAY and IS_LIST would have even more constraints. IS_SEQ would have similar constraints. But the root problem with all of these is the massive ambiguity that results from a typeless system. Is (a) a one-element tuple or a one-element sequence? Is (a, b) a two- element tuple or a one-element variadic sequence? Is (3, (a, b, c)) a three-element array, a two-element tuple, or a one-element variadic sequence? These are all questions that cannot be answered without context (i.e. meaning) that is not present in the structural form of the input. Further, all of these various forms arise naturally in various contexts--these aren't corner cases. Aside from all implementability issues, one could say: IS_ARRAY ( (3, (a, b, c)) ) // 1 IS_SEQ ( (3, (a, b, c)) ) // 1 IS_TUPLE ( (3, (a, b, c)) ) // 1 IS_ARRAY ( abc ) // 0 IS_SEQ ( abc ) // 0 IS_TUPLE ( abc ) // 0 ...but, because of the ambiguity (and, in some cases, lack of implementability), you cannot dispatch on arrays vs. lists vs. sequences vs. tuples. Instead, you can only dispatch on "data structure which I am already expecting" vs. "not a data structure" and that is where IS_VARIADIC comes in because that already allows the distinction. For example, let's say you have an interface MACRO(a) where 'a' can be either a single element of whatever domain you're targeting or it can be a tuple of elements for whatever domain you're targeting. (For the sake of argument, let's say that domain is integers.) So, both MACRO(1) and MACRO((1, 2, 3)) are allowed. What isn't allowed is something like MACRO ((1, 2, 3) 4). If, for the particular domain, that (or something like it) should be allowed, then that is a different, domain-specific data structure which is outside the purview of the pp-lib. However, if it isn't allowed (as is typical), IS_VARIADIC already distinguishes between the two allowed scenarios and suffers none of the issues associated with detecting the difference between (1, 2, 3) and (1, 2, 3) 4. Another example, which *may* be valid in a particular domain, is initialization of a "real" data structure from variadic data. In that case, one might have an interface that accepts any of MACRO(1), MACRO(1, 2), MACRO(1, 2, 3), etc.. However, that should be immediately converted to a real data structure (e.g. tuple or sequence) and subsequently processed. However, whether that is sound is highly dependent on the domain of elements. For your case, that domain covers C++ types. There we already know that we have "open" commas (at least as far as the preprocessor is concerned), and we already know that variadic data is not a suitable transmission mechanism for these without encoding. Note that I'm not implying that there are currently better data structures in the pp-lib as pp-lib sequences don't allow variadic elements, but that is where the work, if it's going to be done, should be done. So, as an example, in the particular case of a list of types, the interface should be MACRO((T)(U)(V)) for any type T, U, and V implemented on top of variadic sequence algorithms. A client can then do something like MACRO (VARIADIC_TO_SEQ(a, b, c)) if they so (unfortunately) choose. Further, they can define their own MY_MACRO that does this: #define MY_MACRO(...) MACRO(VARIADIC_TO_SEQ(__VA_ARGS__)) The fundamental issue here is really whether making macros invocations look like they are not macro invocations is a worthwhile goal as opposed to an incidental and superficial similarity. IMO, making macro invocations look like regular function calls--on purpose, rather than incidentally--is *never*, under *any* circumstances, a worthwhile goal. That applies to things like the above, but also the even worse scenarios where people write macros where they bend over backward (e.g. do loop wrappers) to force a semicolon outside the invocation. #define MACRO(x) \ do { \ /* whatever */ \ } while (false) \ /**/ void f() { int x = 10; MACRO(x); } Pure evil. Bad design. Leads to all of the problems that have produced widespread over-generalizations such as "macros are evil." Macros aren't evil, the above is evil. As is *any* motivation whatsoever to make a macro invocation look like the underlying language. The macro replacement mechanism (really, the preprocessor as a whole) is a different language whose input is the source code and whose output is the underlying language. In a sense, it is no different than a DSEL. A DSEL is a different language embedded in a host language that (typically) better describes the particular domain than the host language does. Why is that considered bad in the context of the preprocessor? Why the constant resistance to treating it as such--especially given the success of the DSEL concept? Regards, Paul Mensonides

On 6/30/2011 11:09 PM, Paul Mensonides wrote:
This notion of a, b, c being a good way to store elements (which are possibly empty sequences of preprocessing tokens and whitespace separations) needs to die. I was just watching some of the Boostcon videos and in one of them (something like Haskell = C++ TMP) there are examples that utilize variadic templates to pass around lists of types. However, in the example, they are "open". I.e. not bounded by something that collects them as a singular entity. I don't have it in front of me, but something like:
template<class, class... T> struct count { enum { value = 1 + count<T...>::value }; };
template<> struct count<> { enum { value = 0 }; };
...but this is terrible. It doesn't take away from the point of the talk, but it should be something like count<typelist<A, B, C>>, not count<A, B, C>.
I'm not disagreeing, but I'd like to know why you believe this is true for templates as well as macros. -- Eric Niebler BoostPro Computing http://www.boostpro.com

On Fri, 01 Jul 2011 08:34:35 -0700, Eric Niebler wrote:
On 6/30/2011 11:09 PM, Paul Mensonides wrote:
...but this is terrible. It doesn't take away from the point of the talk, but it should be something like count<typelist<A, B, C>>, not count<A, B, C>.
I'm not disagreeing, but I'd like to know why you believe this is true for templates as well as macros.
I'd go further and say that it would be terrible to use variadic argument lists (the function parameter kind, not the template parameter kind) to as runtime data structures also. Off the top of my head, here are some reasons: 1) It forces a particular argument order. By itself, this isn't the end of the world, but either tends to break symmetries or tends to require argument orders to change on a bunch of other things. 2) It does not play well with overloading (via number of arguments with macros--which you can do, via specialization of templates, or via plain overloading of functions). 3) It frequently destroys the ability to use default arguments (which could be accounted for if it weren't for #2). 4) It does not work when multiple data structures need to be passed (e.g. Cartesian products). 5) It removes the ability to use the *single* variadic clump for other stuff. I don't have a problem with variadic data used to initialize regular data structures in the right contexts. For example, make_tuple(a, b, c). (I do believe, however, that std::initializer_list<T> is a misfeature. I personally think the { a, b, c } should have been mapped onto a constructor call taking a, b, and c--which may or may not use variadic templates). Regards, Paul Mensonides

On Fri, 01 Jul 2011 22:44:42 +0000, Paul Mensonides wrote:
1) It forces a particular argument order. By itself, this isn't the end of the world, but either tends to break symmetries or tends to require argument orders to change on a bunch of other things. 2) It does not play well with overloading (via number of arguments with macros--which you can do, via specialization of templates, or via plain overloading of functions). 3) It frequently destroys the ability to use default arguments (which could be accounted for if it weren't for #2). 4) It does not work when multiple data structures need to be passed (e.g. Cartesian products). 5) It removes the ability to use the *single* variadic clump for other stuff.
6) Such a data structure cannot nest.
Regards, Paul Mensonides

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 7/1/2011 4:01 PM, Paul Mensonides wrote:
On Fri, 01 Jul 2011 22:44:42 +0000, Paul Mensonides wrote:
1) It forces a particular argument order. By itself, this isn't the end of the world, but either tends to break symmetries or tends to require argument orders to change on a bunch of other things. 2) It does not play well with overloading (via number of arguments with macros--which you can do, via specialization of templates, or via plain overloading of functions). 3) It frequently destroys the ability to use default arguments (which could be accounted for if it weren't for #2). 4) It does not work when multiple data structures need to be passed (e.g. Cartesian products). 5) It removes the ability to use the *single* variadic clump for other stuff.
6) Such a data structure cannot nest.
All good points. Thanks, - -- Eric Niebler BoostPro Computing http://www.boostpro.com -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.17 (MingW32) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iQEcBAEBAgAGBQJODlLRAAoJEAeJsEDfjLbX0AQIAI4BoKJSQ7qnX4QDYoequX55 DGyu+d7uox8RdpC2GUjGwSigQLNV87+weTx5ysrbbnSWBrpyQftlgLfzUVX3rdlg sN2+7IYwpVbMdHrUMWbreamoRUB/kDXmul1gtpaUqGI9KdIklSDjfwka3xBuKkW+ oaCan6LKop2iZfuMJHR0zFtqyYjqjzix9N03zhoS7uGxj0boUwEHBS+yQQcDLYsI kDb9AujP8Lqctxb9NSOuesMsk7sJFLd0/xyiGkeDFRxxWQUyXzzg0o9cF9G+ppcq /8WmHVWWRt5Fe2mjTVmb9b3KbjaqSPlrFLQXYUm4Z67/OSZ48l1toprl3qkUA4g= =6yD5 -----END PGP SIGNATURE-----

On 07/02/2011 12:44 AM, Paul Mensonides wrote:
(I do believe, however, that std::initializer_list<T> is a misfeature. I personally think the { a, b, c } should have been mapped onto a constructor call taking a, b, and c--which may or may not use variadic templates).
Both are possible in C++0x. That's how you initialize tuples. Unary tuples cause somewhat of a problem though.

On Sat, 02 Jul 2011 01:07:04 +0200, Mathias Gaunard wrote:
On 07/02/2011 12:44 AM, Paul Mensonides wrote:
(I do believe, however, that std::initializer_list<T> is a misfeature. I personally think the { a, b, c } should have been mapped onto a constructor call taking a, b, and c--which may or may not use variadic templates).
Both are possible in C++0x. That's how you initialize tuples.
The { a, b, c } syntax does not map onto constructors. It maps onto std::initializer_list<T> for some particular (and unique) T. With C++0x, T x { U(), U(), U() }; // or whatever the exact syntax is maps onto a constructor T(std::initializer_list<U>). (I haven't played around with the details enough to remember off hand the exact semantics, so bear that in mind.) However, T x { U(), V(), W() }; typically maps onto epic fail. IMHO, std::initializer_list<T> should not exist as a language level type. Variadic templates are enough provided the language maps the above syntax directly to a constructor invocation. E.g. T x { a, b, c } mapping to T(a, b, c). With that, you could have done everything that std::initializer_list<T> could do and much more. (E.g. initialize a tuple containing values of differing types.) You could even have added tools at the library level to make it easier to write the constructors for non-expert users. Given that, C's designated initializers (et al) could have been added to C ++ as a special case of keyword arguments which, in turn, could have been extended to regular functions, not just constructors. Regards, Paul Mensonides

On 07/02/2011 01:55 AM, Paul Mensonides wrote:
On Sat, 02 Jul 2011 01:07:04 +0200, Mathias Gaunard wrote:
On 07/02/2011 12:44 AM, Paul Mensonides wrote:
(I do believe, however, that std::initializer_list<T> is a misfeature. I personally think the { a, b, c } should have been mapped onto a constructor call taking a, b, and c--which may or may not use variadic templates).
Both are possible in C++0x. That's how you initialize tuples.
The { a, b, c } syntax does not map onto constructors.
Yes it does. {} has been unified to be the same as constructors in C++0x. You can do tuple<int, double> t {1, 2.}; but unforunately you cannot do tuple<int, double> t = {1, 2.}; because tuple::tuple(int&&, double&&) is explicit (arguably a bug, it should only be explicit in the unary case). Both cases work with pair<int, double> (which is very important when you want to initialize maps).
It maps onto std::initializer_list<T> for some particular (and unique) T.
There are special overloading resolution rules for initializer_list that allows the two. But then I've already said this. If you don't want to believe me, I invite you to take a look at the working draft for C++0x standard at section 8.5.4.

On Sat, 02 Jul 2011 11:25:02 +0200, Mathias Gaunard wrote:
On 07/02/2011 01:55 AM, Paul Mensonides wrote:
The { a, b, c } syntax does not map onto constructors.
Yes it does. {} has been unified to be the same as constructors in C++0x.
If this is true, great! I stand corrected. Regards, Paul Mensonides

On 02/07/11 10:25, Mathias Gaunard wrote:
On 07/02/2011 01:55 AM, Paul Mensonides wrote:
On Sat, 02 Jul 2011 01:07:04 +0200, Mathias Gaunard wrote:
On 07/02/2011 12:44 AM, Paul Mensonides wrote:
(I do believe, however, that std::initializer_list<T> is a misfeature. I personally think the { a, b, c } should have been mapped onto a constructor call taking a, b, and c--which may or may not use variadic templates).
Both are possible in C++0x. That's how you initialize tuples.
The { a, b, c } syntax does not map onto constructors.
Yes it does. {} has been unified to be the same as constructors in C++0x.
You can do tuple<int, double> t {1, 2.}; but unforunately you cannot do tuple<int, double> t = {1, 2.}; because tuple::tuple(int&&, double&&) is explicit (arguably a bug, it should only be explicit in the unary case).
Both cases work with pair<int, double> (which is very important when you want to initialize maps).
It maps onto std::initializer_list<T> for some particular (and unique) T.
There are special overloading resolution rules for initializer_list that allows the two.
But then I've already said this. If you don't want to believe me, I invite you to take a look at the working draft for C++0x standard at section 8.5.4.
I've just been reading the standard and playing around with gcc 4.5.2, and I have to say the results are a bit confusing. class A {}; typedef std::vector<int> V; V v1{size_t(10)}; // vector of size 1 V v2{size_t(10), 10}; // vector of size 2 V v3(size_t(10), 10); // vector of size 10 V v4{10, 10}; // vector of size 2 typedef std::vector<A> VA; VA va1{size_t(10)}; // vector of size 10 //VA va2{size_t(10), A()}; // compile error VA va3(size_t(10), A()); // vector of size 10 VA va4{A(), A()}; // vector of size 2 Two things in particular surprise me: 1. That the construction of va2 is a compile error. I feel that the elements of the initializer lists being of different types should prevent the consideration of initializer-list constructors and fall back to normal constructors. 2. That the construction of v1 prefers V(initializer_list<int>) over V(size_t). I think the crux of the problem is the section [over.match.list] in N3290, where it says: "Initially, the candidate functions are the initializer-list constructors (8.5.4) of the class T and the argument list consists of the initializer list as a single argument." but I can't find described there or in [dcl.init.list] (8.5.4) under what circumstances initializer list constructors are discarded without error due to the elements not being of the right type. It clearly happens sometimes (else the construction of va1 would be an error) but not always (else the construction of va2 would not be an error). Can anyone point me to the relevant text? John Bytheway

On 7/1/2011 6:44 PM, Paul Mensonides wrote:
On Fri, 01 Jul 2011 08:34:35 -0700, Eric Niebler wrote:
On 6/30/2011 11:09 PM, Paul Mensonides wrote:
...but this is terrible. It doesn't take away from the point of the talk, but it should be something like count<typelist<A, B, C>>, not count<A, B, C>.
I'm not disagreeing, but I'd like to know why you believe this is true for templates as well as macros.
I'd go further and say that it would be terrible to use variadic argument lists (the function parameter kind, not the template parameter kind) to as runtime data structures also. Off the top of my head, here are some reasons:
1) It forces a particular argument order. By itself, this isn't the end of the world, but either tends to break symmetries or tends to require argument orders to change on a bunch of other things. 2) It does not play well with overloading (via number of arguments with macros--which you can do, via specialization of templates, or via plain overloading of functions). 3) It frequently destroys the ability to use default arguments (which could be accounted for if it weren't for #2). 4) It does not work when multiple data structures need to be passed (e.g. Cartesian products). 5) It removes the ability to use the *single* variadic clump for other stuff.
I don't have a problem with variadic data used to initialize regular data structures in the right contexts. For example, make_tuple(a, b, c). (I do believe, however, that std::initializer_list<T> is a misfeature. I personally think the { a, b, c } should have been mapped onto a constructor call taking a, b, and c--which may or may not use variadic templates).
I agree that using variadic argument lists as opposed to a data structure containing the data ( list, vector, etc. ) is a poor way to design in general. But sometimes one creates interfaces with which programmers are more comfortable just for the sake of end-user ease. This goes back discussions about variadic data in macros being a more natural way of passing data to macros than pp-lib data structures. When i created VMD, and subsequently worked with you to add variadic data to pp-lib, I was always quick to acknowledge that my main reason for doing so was almost entirely to satisfy end-user expectations of the way macro parameters are normally passed. Other than that variadic data in macros holds no advantage to pp-lib data structures and can generally be ignored. In the same way a designer may decide to create fairly simple functionality using variadic argument lists, just to satsfy end-user programmer expectations. While in the vast majority of cases it should be avoided for all the reasons you give above, and mostly because it is just a poor way of designing software of any complexity.

On Fri, 01 Jul 2011 20:13:19 -0400, Edward Diener wrote:
I agree that using variadic argument lists as opposed to a data structure containing the data ( list, vector, etc. ) is a poor way to design in general. But sometimes one creates interfaces with which programmers are more comfortable just for the sake of end-user ease. This goes back discussions about variadic data in macros being a more natural way of passing data to macros than pp-lib data structures. When i created VMD, and subsequently worked with you to add variadic data to pp-lib, I was always quick to acknowledge that my main reason for doing so was almost entirely to satisfy end-user expectations of the way macro parameters are normally passed. Other than that variadic data in macros holds no advantage to pp-lib data structures and can generally be ignored.
In the same way a designer may decide to create fairly simple functionality using variadic argument lists, just to satsfy end-user programmer expectations. While in the vast majority of cases it should be avoided for all the reasons you give above, and mostly because it is just a poor way of designing software of any complexity.
And my response is the same as always: the ease-of-use argument is a red herring. End user expectations are often misguided, and doing something wrong, on purpose, to fulfill those expectations is bad design and simply perpetuates misguided expectations. Input via pp-lib sequence is insignificantly different in terms of number of typed characters. The difference is typically two parentheses--one at the beginning and one at the end (", " is the same number of characters as ")("). Same thing for tuples. Further, it isn't particularly more or less readable--unless the user has no idea that they are writing code in a different language-- which is the real problem. Perpetual hand-holding perpetuates the problem. A prerequisite of a writing in a language is knowledge of *what* language one is writing. Things that intentionally hide the fact that a different language is being used simply perpetuate the underlying problem of users thinking that the there aren't two languages (that have drastically different semantics). The solution is not hand-holding, it's education--education which won't happen while the hand-holding persists. That is not to say that initialization by way of variadics is in and of itself good or bad. Rather it's the *motivation* to make it look like the underlying language that is bad, and this particular ease-of-use argument falls into that category. There may well be other motivations that select one form of input over another--including variadics. As an example, let's say there is a macro that takes a sequence of types and does something with each, but also uses the entire thing as a whole without processing. E.g. #define MACRO(...) \ /* do stuff for each "element" of __VA_ARGS__ */ \ std::tuple<__VA_ARGS__> xyz; \ /**/ Here there is a potentially compelling reason to use the __VA_ARGS__ directly. Otherwise, you'd have to convert the input data structure to a comma-separated list of types to pass to the tuple template. A motivation along these lines is potentially valid, but that's not because a ill-conceived argument based on ease-of-use (not that all ease-of-use- arguments are ill-conceived), but because of a ease-of-implementation argument. Regards, Paul Mensonides

And my response is the same as always: the ease-of-use argument is a red herring. End user expectations are often misguided, and doing something wrong, on purpose, to fulfill those expectations is bad design and simply perpetuates misguided expectations. Input via pp-lib sequence is insignificantly different in terms of number of typed characters. The difference is typically two parentheses--one at the beginning and one at the end (", " is the same number of characters as ")(").
As a pp-lib user, I find it much more cumbersome to write "MY_MACRO((a)(b)(c))" than "MY_MACRO(a, b, c)" - primarily because the latter requires a lot less keyboard acrobatics - and I have written my own equivalent of VARIADIC_TO_SEQ to allow me to write the latter. Nate.

On Sat, 02 Jul 2011 01:39:38 +0000, Nathan Ridge wrote:
And my response is the same as always: the ease-of-use argument is a red herring. End user expectations are often misguided, and doing something wrong, on purpose, to fulfill those expectations is bad design and simply perpetuates misguided expectations. Input via pp-lib sequence is insignificantly different in terms of number of typed characters. The difference is typically two parentheses--one at the beginning and one at the end (", " is the same number of characters as ")(").
As a pp-lib user, I find it much more cumbersome to write "MY_MACRO((a)(b)(c))" than "MY_MACRO(a, b, c)" - primarily because the latter requires a lot less keyboard acrobatics - and I have written my own equivalent of VARIADIC_TO_SEQ to allow me to write the latter.
Keyboard acrobatics? I thought programmers were the last of the breed that could type all of those special characters without evening thinking about it. :) In any case, I'd bet that this has a lot more to do with familiarity (even muscle familiarity) than it does with acrobatics. I do both all of the time and because I'm used to both, the difference in keystrokes is irrelevant. Further, it is much easier to work with sequences in debugging contexts because it is easier to compose them and (slightly) easier remove elements (actually removing or via comments). E.g. #define A (1)(2)(3) #ifndef NDEBUG #define B (4)(5)(6) #else #define B #endif MY_MACRO(A B) What do you do with sequences of C++ types which may contain open commas? The bottom line is that MY_MACRO(a, b, c) does not scale to the general case. Neither does MY_MACRO((a, b, c)), though it gets closer (though not for C++ types). The pp-lib has to provide infrastructure to support the general case, not a bunch of highly specialized cases. Regards, Paul Mensonides

On 07/01/2011 08:09 AM, Paul Mensonides wrote:
For better variadic support, what's needed most are a few low-level macros such as IS_VARIADIC (small change) and a variadic/placemarker sequence implementation (large, though possibly not difficult, change). This notion of a, b, c being a good way to store elements (which are possibly empty sequences of preprocessing tokens and whitespace separations) needs to die. I was just watching some of the Boostcon videos and in one of them (something like Haskell = C++ TMP) there are examples that utilize variadic templates to pass around lists of types. However, in the example, they are "open". I.e. not bounded by something that collects them as a singular entity. I don't have it in front of me, but something like:
template<class, class... T> struct count { enum { value = 1 + count<T...>::value }; };
template<> struct count<> { enum { value = 0 }; };
...but this is terrible. It doesn't take away from the point of the talk, but it should be something like count<typelist<A, B, C>>, not count<A, B, C>.
Yes, if I remember well Dave made a comment like that during the talk and I think they agreed it would probably be a better mapping but that he wanted to keep things simple for the presentation. When you try to map functions to meta-functions, it's best if a single "list" argument stays a single "typelist" argument as well. Otherwise you have obvious problems when you want to pass multiple lists to a function. There are a couple of languages, though, where calling a function with a list of N arguments is the same as calling it with N arguments, and there is no way to pass two distinct lists within using a delimiter argument. CMake is an example of this.
participants (11)
-
Edward Diener
-
Eric Niebler
-
Jeffrey Lee Hellrung, Jr.
-
John Bytheway
-
lcaminiti
-
Lorenzo Caminiti
-
Mathias Gaunard
-
Nathan Ridge
-
Olaf van der Spek
-
Paul Mensonides
-
Stephan T. Lavavej