[Boost-users] [preprocessor] removing parentheses

317 views
Skip to first unread message

Edward Diener

unread,
Aug 4, 2010, 4:05:57 PM8/4/10
to boost...@lists.boost.org
I have a single macro parameter which allows its passed value to contain
commas. Therefore the user of the macro needs parentheses around the
parameter if it contains one or more commas ( to does not have to ).
When processing this parameter in a macro I would like to remove the
outer parentheses if they are there before passing the value on for
further processing. Is there a way to do this using some preprocessor
library macro ?

_______________________________________________
Boost-users mailing list
Boost...@lists.boost.org
http://lists.boost.org/mailman/listinfo.cgi/boost-users

Daniel Bradburn

unread,
Aug 4, 2010, 5:09:18 PM8/4/10
to boost users mailing list
I'm not sure without seeing exactly what you are trying to do, but perhaps


or


Could help you.

> To: boost...@lists.boost.org
> From: eldi...@tropicsoft.com
> Date: Wed, 4 Aug 2010 16:05:57 -0400
> Subject: [Boost-users] [preprocessor] removing parentheses

Edward Diener

unread,
Aug 4, 2010, 5:38:28 PM8/4/10
to boost...@lists.boost.org
On 8/4/2010 5:09 PM, Daniel Bradburn wrote:
> I'm not sure without seeing exactly what you are trying to do, but perhaps
>
> http://www.boost.org/doc/libs/1_43_0/libs/preprocessor/doc/ref/tuple_rem.html
>
> or
>
> http://www.boost.org/doc/libs/1_43_0/libs/preprocessor/doc/ref/tuple_rem_ctor.html
>
> Could help you.

Except that:

1) I do not know ( or normally care ) how many commas are in the
parenthesized value ( ie. size of the tuple )

2) The value can be passed without any parentheses and therefore not be
a tuple. For this second problem I can force the end-user always to put
parentheses around the passed value, even if it does not need it to form
a single macro value. But 1) would still remain a problem. Of course I
could solve 1) by forcing the end-user to also pass the number of commas
in the parenthesized value as a separate template parameter, but I think
that is too much of a burden for the end-user.

I just want the end-user to pass the value as a single macro parameter,
and to use the value without the outer parentheses if the value contains
commas. But perhaps this is just impossible to do with C++'s macro
facilities. The preprocessing library is so great I was hoping it could
even solve this problem. In reality I may not need to strip off the
parentheses from the value ( which in my particular case forms part of a
C++ declaration ), since redundant parentheses almost ( possibly ) never
causes a syntax error in C++.

It does seems as if the preprocessor library should have the
functionality I require since it is able to extract a value from a
sequence via BOOST_PP_SEQ_ELEM, and a sequence can be in the simple form
of '(value)'. However my tests show that if I pass a non-sequence, such
as just 'value' to BOOST_PP_SEQ_ELEM, the compiler gives a warning and
the result is bogus.

John B. Turpish

unread,
Aug 4, 2010, 7:07:22 PM8/4/10
to boost...@lists.boost.org
On Wed, Aug 4, 2010 at 4:05 PM, Edward Diener <eldi...@tropicsoft.com> wrote:
> I have a single macro parameter which allows its passed value to contain
> commas. Therefore the user of the macro needs parentheses around the
> parameter if it contains one or more commas ( to does not have to ). When
> processing this parameter in a macro I would like to remove the outer
> parentheses if they are there before passing the value on for further
> processing. Is there a way to do this using some preprocessor library macro
> ?

Have you considered using a variadic macro? I hear they're not
available for all C++ precompilers, but it may do what you want:
Instead of
#define YOUR_MACRO( NOCOMMASALLOWED ) NOCOMMASALLOWED
you might use
#define YOUR_MACRO( ... ) __VA_ARGS__
I know it's only "one" argument you're after, but this would at least
pull the commas through in-tact.

Edward Diener

unread,
Aug 5, 2010, 7:15:17 AM8/5/10
to boost...@lists.boost.org
On 8/4/2010 7:07 PM, John B. Turpish wrote:
> On Wed, Aug 4, 2010 at 4:05 PM, Edward Diener<eldi...@tropicsoft.com> wrote:
>> I have a single macro parameter which allows its passed value to contain
>> commas. Therefore the user of the macro needs parentheses around the
>> parameter if it contains one or more commas ( to does not have to ). When
>> processing this parameter in a macro I would like to remove the outer
>> parentheses if they are there before passing the value on for further
>> processing. Is there a way to do this using some preprocessor library macro
>> ?
>
> Have you considered using a variadic macro? I hear they're not
> available for all C++ precompilers, but it may do what you want:
> Instead of
> #define YOUR_MACRO( NOCOMMASALLOWED ) NOCOMMASALLOWED
> you might use
> #define YOUR_MACRO( ... ) __VA_ARGS__
> I know it's only "one" argument you're after, but this would at least
> pull the commas through in-tact.

Variadic macros would indeed be a solution if the compiler(s) I am using
supported that feature. But I am really trying to do work for inclusion
into Boost itself and very few compilers support variadic macros as yet.

Steven Watanabe

unread,
Aug 5, 2010, 1:47:10 PM8/5/10
to boost...@lists.boost.org
AMDG

Edward Diener wrote:
> Variadic macros would indeed be a solution if the compiler(s) I am
> using supported that feature. But I am really trying to do work for
> inclusion into Boost itself and very few compilers support variadic
> macros as yet.

MSVC and gcc have both supported variadic macros for a while.

In Christ,
Steven Watanabe

Steven Watanabe

unread,
Aug 5, 2010, 1:50:22 PM8/5/10
to boost...@lists.boost.org
AMDG

Edward Diener wrote:
> 1) I do not know ( or normally care ) how many commas are in the
> parenthesized value ( ie. size of the tuple )
>
> 2) The value can be passed without any parentheses and therefore not
> be a tuple. For this second problem I can force the end-user always to
> put parentheses around the passed value, even if it does not need it
> to form a single macro value. But 1) would still remain a problem. Of
> course I could solve 1) by forcing the end-user to also pass the
> number of commas in the parenthesized value as a separate template
> parameter, but I think that is too much of a burden for the end-user.
>
> I just want the end-user to pass the value as a single macro
> parameter, and to use the value without the outer parentheses if the
> value contains commas. But perhaps this is just impossible to do with
> C++'s macro facilities. The preprocessing library is so great I was
> hoping it could even solve this problem. In reality I may not need to
> strip off the parentheses from the value ( which in my particular case
> forms part of a C++ declaration ), since redundant parentheses almost
> ( possibly ) never causes a syntax error in C++.
>
> It does seems as if the preprocessor library should have the
> functionality I require since it is able to extract a value from a
> sequence via BOOST_PP_SEQ_ELEM, and a sequence can be in the simple
> form of '(value)'. However my tests show that if I pass a
> non-sequence, such as just 'value' to BOOST_PP_SEQ_ELEM, the compiler
> gives a warning and the result is bogus.

The processor library doesn't support it, since the solution requires
variadic macros. The preprocessor output from the following seems
to be correct with msvc 2005 and gcc 4.4.1

#define CAT(x, y) CAT_I(x, y)
#define CAT_I(x, y) x ## y

#define APPLY(macro, args) APPLY_I(macro, args)
#define APPLY_I(macro, args) macro args

#define STRIP_PARENS(x) EVAL((STRIP_PARENS_I x), x)
#define STRIP_PARENS_I(...) 1,1

#define EVAL(test, x) EVAL_I(test, x)
#define EVAL_I(test, x) MAYBE_STRIP_PARENS(TEST_ARITY test, x)

#define TEST_ARITY(...) APPLY(TEST_ARITY_I, (__VA_ARGS__, 2, 1))
#define TEST_ARITY_I(a,b,c,...) c

#define MAYBE_STRIP_PARENS(cond, x) MAYBE_STRIP_PARENS_I(cond, x)
#define MAYBE_STRIP_PARENS_I(cond, x) CAT(MAYBE_STRIP_PARENS_, cond)(x)

#define MAYBE_STRIP_PARENS_1(x) x
#define MAYBE_STRIP_PARENS_2(x) APPLY(MAYBE_STRIP_PARENS_2_I, x)
#define MAYBE_STRIP_PARENS_2_I(...) __VA_ARGS__

STRIP_PARENS(this is a test)
STRIP_PARENS((a,b,c))

In Christ,
Steven Watanabe

Edward Diener

unread,
Aug 5, 2010, 2:42:38 PM8/5/10
to boost...@lists.boost.org
On 8/5/2010 1:47 PM, Steven Watanabe wrote:
> AMDG
>
> Edward Diener wrote:
>> Variadic macros would indeed be a solution if the compiler(s) I am
>> using supported that feature. But I am really trying to do work for
>> inclusion into Boost itself and very few compilers support variadic
>> macros as yet.
>
> MSVC and gcc have both supported variadic macros for a while.

Regarding MSVC, I have really been asleep regarding variadic macros.
Thanks for awakening me.

Edward Diener

unread,
Aug 5, 2010, 2:59:23 PM8/5/10
to boost...@lists.boost.org
On 8/5/2010 1:47 PM, Steven Watanabe wrote:
> AMDG
>
> Edward Diener wrote:
>> Variadic macros would indeed be a solution if the compiler(s) I am
>> using supported that feature. But I am really trying to do work for
>> inclusion into Boost itself and very few compilers support variadic
>> macros as yet.
>
> MSVC and gcc have both supported variadic macros for a while.

What is the boost configuration macro for this feature ? I searched for
'variadic' in the config macro page but did not find anything for
variadic macros.

John B. Turpish

unread,
Aug 5, 2010, 4:49:19 PM8/5/10
to boost...@lists.boost.org
On Thu, Aug 5, 2010 at 1:47 PM, Steven Watanabe <watan...@gmail.com> wrote:
>
> MSVC and gcc have both supported variadic macros for a while.
>
> In Christ,
> Steven Watanabe

Correct me if I'm wrong (wouldn't surprise me), but aren't variadic
macros technically a C99 thing, and from a C++ perspective always an
extension to the language?

If that's the case, and he's developing something he wants to share
with users of many different platforms and compilers, I completely
understand why it's not a very good solution.

Edward Diener

unread,
Aug 6, 2010, 11:22:14 AM8/6/10
to boost...@lists.boost.org

I can not figure out how this code works. Evidently the rules for
recursive macro invocation eludes me, no matter how many times I have
read the 16.13.1 in the C++ working draft.

Steven Watanabe

unread,
Aug 6, 2010, 12:40:07 PM8/6/10
to boost...@lists.boost.org
AMDG

Alright. Here's stepping through the evaluation
of the two macro invocations. (I may have the evaluation
order slightly wrong, but it doesn't affect the final
result.)

STRIP_PARENS(this is a test)
EVAL((STRIP_PARENS_I this is a test), this is a test)
At this point the first argument is either STRIP_PARENS_I
followed by the original argument or it is 1,1. We can distinguish
the two by checking the size as a tuple.
EVAL_I((STRIP_PARENS_I this is a test), this is a test)
MAYBE_STRIP_PARENS(TEST_ARITY (STRIP_PARENS_I this is a test), this is a
test)
Now we expand TEST_ARITY which returns the number of elements in its
argument. In this case, the result will be 1.
APPLY(TEST_ARITY_I, (STRIP_PARENS_I this is a test, 2, 1))
APPLY_I(TEST_ARITY_I, (STRIP_PARENS_I this is a test, 2, 1))
TEST_ARITY_I (STRIP_PARENS_I this is a test, 2, 1)
TEST_ARITY_I (STRIP_PARENS_I this is a test, 2, 1)
1
Now we can go back to MAYBE_STRIP_PARENS.
We're going to switch on the tuple size (which we just
found)to decide whether we need to remove parentheses.
MAYBE_STRIP_PARENS(1, this is a test)
MAYBE_STRIP_PARENS_I(1, this is a test)
CAT(MAYBE_STRIP_PARENS_, 1)(this is a test)
MAYBE_STRIP_PARENS_1(this is a test)
this is a test.

In the second case we get
EVAL((STRIP_PARENS_I (a,b,c)), (a,b,c))
STRIP_PARENS_I can be expanded to get
EVAL((1,1), (a,b,c))
Now we we check the arity, we end up with
TEST_ARITY_I (1,1, 2, 1)
which expands to 2, and we select
MAYBE_STRIP_PARENS_2((a,b,c))
the expansion of which should be straightforward

In Christ,
Steven Watanabe

Edward Diener

unread,
Aug 6, 2010, 1:35:41 PM8/6/10
to boost...@lists.boost.org

Many thanks !

Reply all
Reply to author
Forward
0 new messages