[preprocessor] BOOST_PP_VARIADIC_SIZE() and g++ in 1.52
I'm trying to use a variadic macro to solve a problem. We use a
third-party function I can't modify -- actually a family of functions
of arbitrary arity. Before each call to that function, I want to
examine and possibly modify its first argument. (So not completely
arbitrary arity: there's always at least one argument.)
What I'd really like is a variadic function. Unfortunately the
compilers we use don't yet support those.
We do have cross-platform support for variadic macros, albeit with
idiosyncratic syntax.
My problem is that I need:
intercept(first, second, third)
to expand to:
targetfunc(transform(first), second, third)
but I need:
intercept(first)
to expand to:
targetfunc(transform(first)) // <= no trailing comma
This is the role of BOOST_PP_COMMA_IF(). In Visual Studio 2010 I can
write BOOST_PP_COMMA_IF(BOOST_PP_VARIADIC_SIZE(__VA_ARGS__)), and the
code behaves as expected.
In g++ 4.1, 4.2 and 4.4, however, my first problem is that
BOOST_PP_VARIADICS is not set by default. When I set it explicitly, as
permitted by the documentation[0], a call such as intercept("first",
"second") (comma required) succeeds, but a call such as
intercept("first") (comma forbidden) fails. Using -E and examining the
preprocessed output from intercept("first") makes clear that
BOOST_PP_COMMA_IF() is expanding to a comma, hence
BOOST_PP_VARIADIC_SIZE() is expanding to nonzero.
In fact, when I change the definition of the intercept() macro below to:
#define intercept(FIRST, ARGS...) \
targetfunc(transform(FIRST) \
, boost::lexical_caststd::string(BOOST_PP_VARIADIC_SIZE(ARGS)))
I see that BOOST_PP_VARIADIC_SIZE() expands to 1 for
intercept("first") as well as for intercept("first", "second").
Is it possible to achieve what I want with my present suite of
compilers? Is there some workaround we could use until (at some point
in the indefinite future) we've upgraded all our compilers so that
even the oldest of them supports variadic functions?
[0] http://www.boost.org/doc/libs/1_52_0/libs/preprocessor/doc/topics.html
================ source code follows ================
#include <iostream>
#include <string>
#include
In fact, when I change the definition of the intercept() macro below to:
#define intercept(FIRST, ARGS...) \ targetfunc(transform(FIRST) \ , boost::lexical_caststd::string(BOOST_PP_VARIADIC_SIZE(ARGS)))
I see that BOOST_PP_VARIADIC_SIZE() expands to 1 for intercept("first") as well as for intercept("first", "second").
As I understand it, it is impossible to reliably detect an empty argument list in all cases, so BOOST_PP_VARIADIC_SIZE() returns 1 for an empty argument list. Take a look at this thread [1] for an explanation and a workaround. Regards, Nate [1] http://boost.2283326.n4.nabble.com/Alternative-implementation-for-BOOST-PP-V...
On Tue, Dec 11, 2012 at 11:16 PM, Nathan Ridge
In fact, when I change the definition of the intercept() macro below to:
#define intercept(FIRST, ARGS...) \ targetfunc(transform(FIRST) \ , boost::lexical_caststd::string(BOOST_PP_VARIADIC_SIZE(ARGS)))
I see that BOOST_PP_VARIADIC_SIZE() expands to 1 for intercept("first") as well as for intercept("first", "second").
As I understand it, it is impossible to reliably detect an empty argument list in all cases, so BOOST_PP_VARIADIC_SIZE() returns 1 for an empty argument list. Take a look at this thread [1] for an explanation and a workaround.
Hmm, am I trying to solve the wrong problem? The briefest explanation of what I want is to take a macro argument list with zero or more arguments and construct a function argument list with one more (initial) argument than that. I just need MACRO() to expand to function(first), but MACRO(anything) to expand to function(first, anything). Is there some more reliable way than BOOST_PP_COMMA_IF(BOOST_PP_VARIADIC_SIZE()) to make the comma appear only when required?
In fact, when I change the definition of the intercept() macro below to:
#define intercept(FIRST, ARGS...) \ targetfunc(transform(FIRST) \ , boost::lexical_caststd::string(BOOST_PP_VARIADIC_SIZE(ARGS)))
I see that BOOST_PP_VARIADIC_SIZE() expands to 1 for intercept("first") as well as for intercept("first", "second").
As I understand it, it is impossible to reliably detect an empty argument list in all cases, so BOOST_PP_VARIADIC_SIZE() returns 1 for an empty argument list. Take a look at this thread [1] for an explanation and a workaround.
Hmm, am I trying to solve the wrong problem?
The briefest explanation of what I want is to take a macro argument list with zero or more arguments and construct a function argument list with one more (initial) argument than that.
I just need MACRO() to expand to function(first), but MACRO(anything) to expand to function(first, anything).
Is there some more reliable way than BOOST_PP_COMMA_IF(BOOST_PP_VARIADIC_SIZE()) to make the comma appear only when required?
The preprocessor only really understand commas and parentheses. So, as far as it's concerned, the definition of "the size of a variadic argument list" is "the number of (top-level) commas in the list plus one". You want to make an additional distinction - in the case where there are no top-level commas, you want to distinguish between the case where there are some tokens present, and the case where there are none. As Paul Mensonides explains in the thread I linked to, this is not possible in the general case. It *is* possible to write a version of BOOST_PP_VARIADIC_SIZE() that works the way you want in many cases, quite possibly including your use cases. I believe Boost.Preprocessor does not provide such a version on principle (because it would not work in all cases). However, nothing stops you from using your own version that does this. Gennadiy Rozental posted such a version in the first post of the thread I linked to. Regards, Nate
On Wed, Dec 12, 2012 at 11:59 AM, Nathan Ridge
It *is* possible to write a version of BOOST_PP_VARIADIC_SIZE() that works the way you want in many cases, quite possibly including your use cases. I believe Boost.Preprocessor does not provide such a version on principle (because it would not work in all cases). However, nothing stops you from using your own version that does this. Gennadiy Rozental posted such a version in the first post of the thread I linked to.
Okay, thank you Nathan, and thank you also Gennadiy. Your version does appear to address my use case.
On 12/12/2012 11:59 AM, Nathan Ridge wrote:
In fact, when I change the definition of the intercept() macro below to:
#define intercept(FIRST, ARGS...) \ targetfunc(transform(FIRST) \ , boost::lexical_caststd::string(BOOST_PP_VARIADIC_SIZE(ARGS)))
I see that BOOST_PP_VARIADIC_SIZE() expands to 1 for intercept("first") as well as for intercept("first", "second").
As I understand it, it is impossible to reliably detect an empty argument list in all cases, so BOOST_PP_VARIADIC_SIZE() returns 1 for an empty argument list. Take a look at this thread [1] for an explanation and a workaround.
Hmm, am I trying to solve the wrong problem?
The briefest explanation of what I want is to take a macro argument list with zero or more arguments and construct a function argument list with one more (initial) argument than that.
I just need MACRO() to expand to function(first), but MACRO(anything) to expand to function(first, anything).
Is there some more reliable way than BOOST_PP_COMMA_IF(BOOST_PP_VARIADIC_SIZE()) to make the comma appear only when required?
The preprocessor only really understand commas and parentheses. So, as far as it's concerned, the definition of "the size of a variadic argument list" is "the number of (top-level) commas in the list plus one".
You want to make an additional distinction - in the case where there are no top-level commas, you want to distinguish between the case where there are some tokens present, and the case where there are none. As Paul Mensonides explains in the thread I linked to, this is not possible in the general case.
It *is* possible to write a version of BOOST_PP_VARIADIC_SIZE() that works the way you want in many cases, quite possibly including your use cases. I believe Boost.Preprocessor does not provide such a version on principle (because it would not work in all cases). However, nothing stops you from using your own version that does this. Gennadiy Rozental posted such a version in the first post of the thread I linked to.
Something like:
#include
On Dec 11, 2012, at 10:19 AM, Nat Linden wrote:
In fact, when I change the definition of the intercept() macro below to:
#define intercept(FIRST, ARGS...) \ targetfunc(transform(FIRST) \ , boost::lexical_caststd::string(BOOST_PP_VARIADIC_SIZE(ARGS)))
I see that BOOST_PP_VARIADIC_SIZE() expands to 1 for intercept("first") as well as for intercept("first", "second").
Is it possible to achieve what I want with my present suite of compilers? Is there some workaround we could use until (at some point in the indefinite future) we've upgraded all our compilers so that even the oldest of them supports variadic functions?
Perhaps something like the following will do what you need? #define intercept(ARGS...) \ BOOST_PP_IIF( \ BOOST_PP_EQUAL(1, BOOST_PP_VARIADIC_SIZE(ARGS)), \ intercept_1, \ intercept_many)(ARGS) where the definitions of intercept_1 and intercept_many should be obvious.
participants (4)
-
Edward Diener
-
Kim Barrett
-
Nat Linden
-
Nathan Ridge