Files
2025-10-25 03:02:53 +03:00

106 lines
5.7 KiB
Markdown
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

[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.2Argument substitution[cpp.subst]")
__VA_OPT__ ( [*pp-tokens*](cpp.pre#nt:pp-tokens "15.1Preamble[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.2Argument 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.2Argument 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.1Preamble[cpp.pre]")[.](#4.sentence-1)
The [*pp-tokens*](cpp.pre#nt:pp-tokens "15.1Preamble[cpp.pre]") of a [*va-opt-replacement*](#nt:va-opt-replacement "15.7.2Argument substitution[cpp.subst]") shall not contain __VA_OPT__[.](#4.sentence-2)
If the [*pp-tokens*](cpp.pre#nt:pp-tokens "15.1Preamble[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.2Argument 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.4The ## operator"), [[cpp.rescan]](cpp.rescan "15.7.5Rescanning 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.1Preamble[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.3The # operator")),
and can be removed by rescanning and further replacement ([[cpp.rescan]](cpp.rescan "15.7.5Rescanning 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.4The ## 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*]