Boost logo

Boost :

From: Paul Mensonides (pmenso57_at_[hidden])
Date: 2003-04-30 22:46:53


Rene Rivera wrote:
>> 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.
>
> I don't see what difference the problem tokens are. If the
> preprocessor
> knows to not parse a specific token sequence you tell it how can it
> be a problem?

Well, how about this:

#define STR(x) STR_(x)
#define STR_(x) #x

STR( + ) // okay: "+"
STR( ( ) // error!
STR( , ) // error!

It is impossible to stringize the comma or one of the parentheses by itself.
Best you can do is this:

STR( () ) // okay: "()"
STR( (,) ) // okay: "(,)"

...which is not what is wanted.

>> #define COMMA() ,
>
> Or define it as:
>
> #define COMMA #escape ","

Yes, or just use __comma__ as Vesa suggested. :)

>> And then pass it through other macros without invoking it:
>>
>> MACRO( COMMA )
>
> No need if defined as above.

Yes, same as __comma__ also. The point being that you only need __comma__,
__lparen__, and __rparen__. You don't need it for anything else.

> You could do:
>
> MACRO( #escape "+" )

Yes, but want we want is:

MACRO(+)
MACRO(__comma__)

For the common case where the comma or parentheses aren't needed for further
expansion. If token-pasting was well-defined for unrelated tokens, you could
force the invocation early in a general fashion if desired.

>> Because you'd get this:
>>
>> R(0) +() R(1) +() R(2)
>
> And would get the desired:
>
> 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)
>
> MACRO( #escape "," ) // R(0) , R(1) , R(2)
> MACRO( #escape " " ) // R(0) R(1) R(2)
> MACRO( #escape "+" ) // R(0) + R(1) + R(2)
> MACRO( #escape ";" ) // R(0) ; R(1) ; R(2)

MACRO(__comma__)
MACRO() // placemarkers from C99
MACRO(+)
MACRO(;)

>> 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
> Did you mean #define OTHER(x) OTHER_I(x) ???

Yes, sorry.

>> #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.
>
> Ahh (after a few minutes of contemplation ;-)... I see that problem.
> Basically there is no general point of macro replacement that will
> solve it in all cases. Currently it's "replace asap", and with the
> __comma__ & #escape it's "replace last".

(I should say, BTW, that given a "strict" preprocessor, I can cause a delay in a
macro's invocation through virtually any number of rescannings. Meaning that,
if I can count the number of rescans for a given argument (which I can also do),
I can delay the invocation of COMMA all the way through to the correct point and
have it expand automatically. However, that is dangerous and ridiculously
fragile.)

> OK, so here's another idea. Let the macro writer/user specify where
> the replacement point is. With lets say an #eval command. The problem
> example above could then be implemented as:
>
> #define OTHER(x) OTHER_I( #eval x )
>
> Or for the user...
>
> OTHER( #eval MACRO(#escape ",") )

The whole point, IMO, is to avoid the need for the intrusive syntax in as many
places as possible--both in the implementation and in the interface. __comma__,
__lparen__, and __rparen__ are the only useful ones--unless you mean to say that
#escape "..." can include arbitrary macros expansions etc. that are delayed
until the last possible moment?

Paul Mensonides


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