Boost logo

Boost :

From: Rene Rivera (grafik666_at_[hidden])
Date: 2003-04-30 22:25:51


[2003-04-30] Paul Mensonides wrote:

>Rene Rivera wrote:
>> [2003-04-30] Paul Mensonides wrote:
>>
>>> 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.

I think I lost you on some of your explanation so bear with me...

>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?

>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)
> ^ ^

OK.

>Because this delineator might be a comma, you have to "abstract" it into an
>invocable macro:
>
>#define COMMA() ,

Or define it as:

    #define COMMA #escape ","

>And then pass it through other macros without invoking it:
>
>MACRO( COMMA )

No need if defined as above.

>Ultimately, however, the macro must be expanded or you'll get this:
>
>R(0) COMMA R(1) COMMA R(2)

Or in the #escape construct:

R(0) #escape "," R(1) #escape "," R(2)

>So, you make the requirement that the delineator must be invocable:
>
>R(0) COMMA() R(1) COMMA() R(2)

And #escape is ultimately invocable only after the macro expansion recursion
finishes.

>Which expands to:
>
>R(0) , R(1) , R(2)

Same.

>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( + )

You could do:

    MACRO( #escape "+" )

>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)

>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) ???
>#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".

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 ",") )

-- grafik - Don't Assume Anything
-- rrivera_at_[hidden] - grafik_at_[hidden]
-- 102708583_at_icq


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