问题
Using Paul Fultz II's solution in the post C-preprocessor recursive macro, I'd like to expand an unlimited number of parenthesized macro arguments, e.g.
#define MY_CHAIN (alpha) (beta) (gamma)
into a comma-separated list which can be passed to a variadic macro, e.g.
CHAIN_COMMA(MY_CHAIN) // alpha, beta, gamma
I'm able to expand into braces [alpha] [beta] [gamma]
and delimit the list with everything I've tried except a comma, alpha :: beta :: gamma
in the example below.
Here is my full (compiling) code:
#include <iostream>
using namespace std;
// unrelated macro utilities
#define SEE(expression) cout << #expression ": " << STR(expression) << endl;
#define CMD(function, ...) function(__VA_ARGS__)
#define STR(s) CMD(STR_, s)
#define STR_(s) #s
// concatenation
#define CAT(x, y) CAT_(x, y)
#define CAT_(x,y) x ## y // error from CHAIN_COMMA: passed 4 arguments
// surround each chain element with square brackets []
#define CHAIN_BRACE(chain) CAT(CHAIN_BRACE_1 chain, _END)
#define CHAIN_BRACE_1(x) [x] CHAIN_BRACE_2
#define CHAIN_BRACE_2(x) [x] CHAIN_BRACE_1
#define CHAIN_BRACE_1_END
#define CHAIN_BRACE_2_END
// separate each chain element with the scope operator ::
#define CHAIN_SCOPE(chain) CAT(CHAIN_SCOPE_0 chain, _END)
#define CHAIN_SCOPE_0(x) x CHAIN_SCOPE_1
#define CHAIN_SCOPE_1(x) :: x CHAIN_SCOPE_2
#define CHAIN_SCOPE_2(x) :: x CHAIN_SCOPE_1
#define CHAIN_SCOPE_0_END
#define CHAIN_SCOPE_1_END
#define CHAIN_SCOPE_2_END
// trouble here: can't separate chain elements with commas
#define CHAIN_COMMA(chain) CAT(CHAIN_COMMA_0 chain, _END) // error
#define CHAIN_COMMA_0(x) x CHAIN_COMMA_1
#define CHAIN_COMMA_1(x) , x CHAIN_COMMA_2
#define CHAIN_COMMA_2(x) , x CHAIN_COMMA_1
#define CHAIN_COMMA_0_END
#define CHAIN_COMMA_1_END
#define CHAIN_COMMA_2_END
// define a custom chain and save various forms of it
#define MY_CHAIN (alpha) (beta) (gamma)
#define MY_BRACES CHAIN_BRACE(MY_CHAIN) // [alpha] [beta] [gamma]
#define MY_SCOPES CHAIN_SCOPE(MY_CHAIN) // alpha :: beta :: gamma
#define MY_COMMAS CHAIN_COMMA(MY_CHAIN) // alpha , beta , gamma
int main() {
SEE(MY_CHAIN);
SEE(MY_BRACES);
SEE(MY_SCOPES);
// SEE(MY_COMMAS); // error: macro "CAT_" passed 4 arguments, but takes just 2
return 0;
}
This outputs:
MY_CHAIN: (alpha) (beta) (gamma)
MY_BRACES: [alpha] [beta] [gamma]
MY_SCOPES: alpha :: beta :: gamma
I tried parenthesizing the comma-separated list but CAT won't append )
to _END
. Any clever ideas to expand into alpha, beta, gamma
?
回答1:
As the comma is both important to your output and is a syntactic element you need to make a substitute comma for outputting.
#define COMMA() ,
We will also need some deferring functions so that COMMA
isn't evaluated immediately.
#define EMPTY()
#define DEFER(id) id EMPTY()
Now we can redefine your two macros into
#define CHAIN_COMMA_1(x) DEFER(COMMA)() x CHAIN_COMMA_2
#define CHAIN_COMMA_2(x) DEFER(COMMA)() x CHAIN_COMMA_1
However your SEE
macro also doesn't like the commas that are placed and so will error for having to many parameters passed.
You can see that this is performing correctly by looking at the output of the preprocessor with the -E
option.
来源:https://stackoverflow.com/questions/49235603/c-preprocessor-iteratively-expand-macro-to-comma-separated-list