|
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