15 Preprocessing directives [cpp]

15.6 Macro replacement [cpp.replace]

15.6.2 Argument substitution [cpp.subst]

va-opt-replacement:
__VA_­OPT__ ( pp-tokens )
After the arguments for the invocation of a function-like macro have been identified, argument substitution takes place.
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 token sequence determined as follows:
  • If the parameter is of the form va-opt-replacement, the replacement preprocessing tokens are the preprocessing token sequence for the corresponding argument, as specified below.
  • Otherwise, the replacement preprocessing tokens are the preprocessing tokens of corresponding argument after all macros contained therein have been expanded.
    The argument's preprocessing tokens are completely macro replaced before being substituted as if they formed the rest of the preprocessing file with no other preprocessing tokens being available.
[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]
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.
[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 in fprintf(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]
The identifier __VA_­OPT__ shall always occur as part of the preprocessing token sequence va-opt-replacement; its closing ) is determined by skipping intervening pairs of matching left and right parentheses in its pp-tokens.
The pp-tokens of a va-opt-replacement shall not contain __VA_­OPT__.
If the pp-tokens would be ill-formed as the replacement list of the current function-like macro, the program is ill-formed.
A va-opt-replacement is treated as if it were a parameter, and the preprocessing token sequence for the corresponding argument is defined as follows.
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.rescan]).
Otherwise, the argument consists of the results of the expansion of the contained pp-tokens as the replacement list of the current function-like macro before removal of placemarker tokens, rescanning, and further replacement.
[Note 1:
The placemarker tokens are removed before stringization ([cpp.stringize]), and can be removed by rescanning and further replacement ([cpp.rescan]).
— end note]
[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]) #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]