C-preprocessor: iteratively expand macro to comma-separated list

别说谁变了你拦得住时间么 提交于 2020-01-13 10:44:11

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!