Boost logo

Boost :

From: Paul Mensonides (pmenso57_at_[hidden])
Date: 2003-04-30 21:29:18


Rene Rivera wrote:
> [2003-04-30] Paul Mensonides wrote:
>
>> David Abrahams wrote:
>>> ** and which I'm not sure is even addressing a real-world problem.
>>> It might be; I am just not sure.
>>
>> It is not something that can't be worked around, but it is a
>> nuisance. Basically, you have to expand a macro to produce a
>> comma--but do it only at the last possible step so it doesn't go
>> through any other macros. The problem is not that so much. Rather,
>> it implies that you have to pass everything else as such an
>> "invocable" entity--which is annoying at best.
>
> If that's the case would not a more general utility to insert/escape
> literals be desirable.

The only problem tokens are , ( ) # and ## (as well as %: and %:%:). Everything
else is fine. The problems with those tokens arise only from the fact they have
special meaning to the syntactic/semantic model of the preprocessor. As I said,
we can work around this problem, but the workaround is not local--i.e. it makes
it necessary to apply the workaround globally an any situation where you might
want to pass one of those tokens.

Say, for example, that you have a repetition construct that takes a "delineator"
argument. I.e. a token (or tokens) to delineate the repetitions:

R(0) , R(1) , R(2)
     ^ ^

Because this delineator might be a comma, you have to "abstract" it into an
invocable macro:

#define COMMA() ,

And then pass it through other macros without invoking it:

MACRO( COMMA )

Ultimately, however, the macro must be expanded or you'll get this:

R(0) COMMA R(1) COMMA R(2)

So, you make the requirement that the delineator must be invocable:

R(0) COMMA() R(1) COMMA() R(2)

Which expands to:

R(0) , R(1) , R(2)

Everything is not too bad so far, but generalization makes it annoying. What if
you want to use + as a separator? You can't do this:

MACRO( + )

Because you'd get this:

R(0) +() R(1) +() R(2)

So, you have to either 1) make a PLUS() macro or 2) use some type of invocable
identity macro:

#define COMMA() ,

#define EMPTY()
#define IDENTITY(x) x EMPTY

MACRO( COMMA ) // R(0) , R(1) , R(2)
MACRO( EMPTY ) // R(0) R(1) R(2)
MACRO( IDENTITY(+) ) // R(0) + R(1) + R(2)
MACRO( IDENTITY(;) ) // R(0) ; R(1) ; R(2)

Etc.

In other words, the "fix" takes over everything that isn't the problem to begin
with. I.e. it is intrusive. There are other options, of course, but all of
them have some type of intrusive drawback--for instance what if you wanted "(("
as a delineator...

Late-bound expansion for __comma__, __lparen__, and __rparen__ would *partially*
solve the problem. However, it would not fix the problem completely. For
instance, if the above result was used as arguments to an other macro:

#define OTHER(x) OTHER_I x
#define OTHER_I(a, b, c) a b c

OTHER( MACRO(__comma__) ) // error

The same caveat applies to parentheses. They permanently become "non-operators"
to the preprocessor which can be a major limitation.

However, they would be so simple to implement that they would still be a good
idea and quite useful in many contexts.

Regards,
Paul Mensonides


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