I'm trying to understand the nitty-gritty details of how the C++ preprocessor works.
Assume we have:
#define LP (
#define F(X) a
The following code then preprocesses to a
:
#define G1(Y) F Y
G1(LP) 1 )
However, the following code preprocesses to F ( 1 )
:
#define G2(Y) F LP
G2(LP) 1 )
Okay, so I guess this makes sense if the LP
argument is already expanded by the time it's fed into the macro.
Except, that's not the case! The following code preprocesses to F "LP" 1 )
, not F "(" 1 )
:
#define G3(Y) F #Y
G3(LP) 1 )
Okay, now I'm confused. What are the rules behind when an open parenthesis is treated as the beginning of a function-like macro invocation?
The C++ preprocessor considers the file to be made of group-parts. This rule is defined as follows:
group-part:
control-line
if-section
text-lines
#
conditionally-supported-directivecontrol-line:
[...]
#
define
identifier lparen identifier-listopt)
replacement-list new-line
[...]lparen:
a(
character not immediately preceded by whitespace
This is why #define Z ()
would not not define a function-like macro, but #define Z()
would for example.
The preprocessor eliminates separating whitespace when expanding macros, so F Y
where Y
expands to LP )
is treated as F()
. Expanding function-like macros is described in [cpp.subst] p1.
The reason why F #Y
behaves differently is that [cpp.subst] exempts #Y
from macro substitution, and instead, the #
operator is applied, meaning that
[...] the original spelling of each preprocessing token in the stringizing argument is retained in the character string literal [...]
In your example, #Y
where Y
expands to "LP"
, because LP
is the original spelling of the argument.