106 lines
5.7 KiB
Markdown
106 lines
5.7 KiB
Markdown
[cpp.subst]
|
||
|
||
# 15 Preprocessing directives [[cpp]](./#cpp)
|
||
|
||
## 15.7 Macro replacement [[cpp.replace]](cpp.replace#cpp.subst)
|
||
|
||
### 15.7.2 Argument substitution [cpp.subst]
|
||
|
||
[va-opt-replacement:](#nt:va-opt-replacement "15.7.2 Argument substitution [cpp.subst]")
|
||
__VA_OPT__ ( [*pp-tokens*](cpp.pre#nt:pp-tokens "15.1 Preamble [cpp.pre]")opt )
|
||
|
||
[1](#1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/preprocessor.tex#L1670)
|
||
|
||
After the arguments for the invocation of a function-like macro have
|
||
been identified, argument substitution takes place[.](#1.sentence-1)
|
||
|
||
For each parameter in the replacement list that is neither
|
||
preceded by a # or ## preprocessing token nor
|
||
followed by a ## preprocessing token, the preprocessing tokens
|
||
naming the parameter are replaced by a preprocessing token sequence determined as follows:
|
||
|
||
- [(1.1)](#1.1)
|
||
|
||
If the parameter is of the form [*va-opt-replacement*](#nt:va-opt-replacement "15.7.2 Argument substitution [cpp.subst]"),
|
||
the replacement preprocessing tokens are the
|
||
preprocessing token sequence for the corresponding argument,
|
||
as specified below[.](#1.1.sentence-1)
|
||
|
||
- [(1.2)](#1.2)
|
||
|
||
Otherwise, the replacement preprocessing tokens are the
|
||
preprocessing tokens of corresponding argument after all
|
||
macros contained therein have been expanded[.](#1.2.sentence-1)
|
||
The argument's
|
||
preprocessing tokens are completely macro replaced before
|
||
being substituted as if they formed the rest of the preprocessing
|
||
translation unit with no other preprocessing tokens being available[.](#1.2.sentence-2)
|
||
|
||
[*Example [1](#example-1)*: #define LPAREN() (#define G(Q) 42#define F(R, X, ...) __VA_OPT__(G R X) )int x = F(LPAREN(), 0, <:-); // replaced by int x = 42; â *end example*]
|
||
|
||
[2](#2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/preprocessor.tex#L1700)
|
||
|
||
An identifier __VA_ARGS__ that occurs in the replacement list
|
||
shall be treated as if it were a parameter, and the variable arguments shall form
|
||
the preprocessing tokens used to replace it[.](#2.sentence-1)
|
||
|
||
[3](#3)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/preprocessor.tex#L1706)
|
||
|
||
[*Example [2](#example-2)*:
|
||
|
||
#define debug(...) fprintf(stderr, __VA_ARGS__)#define showlist(...) puts(#__VA_ARGS__)#define report(test, ...) ((test) ? puts(#test) : printf(__VA_ARGS__)) debug("Flag");
|
||
debug("X = %d\n", x);
|
||
showlist(The first, second, and third items.);
|
||
report(x>y, "x is %d but y is %d", x, y); results infprintf(stderr, "Flag");
|
||
fprintf(stderr, "X = %d\n", x);
|
||
puts("The first, second, and third items.");((x>y) ? puts("x>y") : printf("x is %d but y is %d", x, y));
|
||
|
||
â *end example*]
|
||
|
||
[4](#4)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/preprocessor.tex#L1726)
|
||
|
||
The identifier __VA_OPT__ shall always occur as part of the preprocessing token sequence[*va-opt-replacement*](#nt:va-opt-replacement "15.7.2 Argument substitution [cpp.subst]");
|
||
its closing ) is determined by skipping
|
||
intervening pairs of matching left and right parentheses
|
||
in its [*pp-tokens*](cpp.pre#nt:pp-tokens "15.1 Preamble [cpp.pre]")[.](#4.sentence-1)
|
||
|
||
The [*pp-tokens*](cpp.pre#nt:pp-tokens "15.1 Preamble [cpp.pre]") of a [*va-opt-replacement*](#nt:va-opt-replacement "15.7.2 Argument substitution [cpp.subst]") shall not contain __VA_OPT__[.](#4.sentence-2)
|
||
|
||
If the [*pp-tokens*](cpp.pre#nt:pp-tokens "15.1 Preamble [cpp.pre]") would be ill-formed
|
||
as the replacement list of the current function-like macro,
|
||
the program is ill-formed[.](#4.sentence-3)
|
||
|
||
A [*va-opt-replacement*](#nt:va-opt-replacement "15.7.2 Argument substitution [cpp.subst]") is treated as if it were a parameter,
|
||
and the preprocessing token sequence for the corresponding
|
||
argument is defined as follows[.](#4.sentence-4)
|
||
|
||
If the substitution of __VA_ARGS__ as neither an operand
|
||
of # nor ## consists of no preprocessing tokens,
|
||
the argument consists of
|
||
a single placemarker preprocessing token ([[cpp.concat]](cpp.concat "15.7.4 The ## operator"), [[cpp.rescan]](cpp.rescan "15.7.5 Rescanning and further replacement"))[.](#4.sentence-5)
|
||
|
||
Otherwise, the argument consists of
|
||
the results of the expansion of the contained [*pp-tokens*](cpp.pre#nt:pp-tokens "15.1 Preamble [cpp.pre]") as the replacement list of the current function-like macro
|
||
before removal of placemarker tokens, rescanning, and further replacement[.](#4.sentence-6)
|
||
|
||
[*Note [1](#note-1)*:
|
||
|
||
The placemarker tokens are removed before stringization ([[cpp.stringize]](cpp.stringize "15.7.3 The # operator")),
|
||
and can be removed by rescanning and further replacement ([[cpp.rescan]](cpp.rescan "15.7.5 Rescanning and further replacement"))[.](#4.sentence-7)
|
||
|
||
â *end note*]
|
||
|
||
[*Example [3](#example-3)*: #define F(...) f(0 __VA_OPT__(,) __VA_ARGS__)#define G(X, ...) f(0, X __VA_OPT__(,) __VA_ARGS__)#define SDEF(sname, ...) S sname __VA_OPT__(= { __VA_ARGS__ })#define EMP
|
||
|
||
F(a, b, c) // replaced by f(0, a, b, c) F() // replaced by f(0) F(EMP) // replaced by f(0) G(a, b, c) // replaced by f(0, a, b, c) G(a, ) // replaced by f(0, a) G(a) // replaced by f(0, a) SDEF(foo); // replaced by S foo; SDEF(bar, 1, 2); // replaced by S bar = { 1, 2 };#define H1(X, ...) X __VA_OPT__(##) __VA_ARGS__ // error: ## may not appear at// the beginning of a replacement list ([[cpp.concat]](cpp.concat "15.7.4 The ## operator"))#define H2(X, Y, ...) __VA_OPT__(X ## Y,) __VA_ARGS__
|
||
H2(a, b, c, d) // replaced by ab, c, d#define H3(X, ...) #__VA_OPT__(X##X X##X) H3(, 0) // replaced by ""#define H4(X, ...) __VA_OPT__(a X ## X) ## b
|
||
H4(, 1) // replaced by a b#define H5A(...) __VA_OPT__()/**/__VA_OPT__()#define H5B(X) a ## X ## b#define H5C(X) H5B(X) H5C(H5A()) // replaced by ab â *end example*]
|