代码之家  ›  专栏  ›  技术社区  ›  Taylor Nichols

C预处理器:将宏迭代展开为逗号分隔的列表

  •  5
  • Taylor Nichols  · 技术社区  · 6 年前

    在帖子中使用Paul Fultz II的解决方案 C-preprocessor recursive macro ,我想扩展无限个带括号的宏参数,例如。

    #define MY_CHAIN (alpha) (beta) (gamma)
    

    输入一个逗号分隔的列表,该列表可以传递给变量宏,例如。

    CHAIN_COMMA(MY_CHAIN) // alpha, beta, gamma
    

    我可以扩展成大括号 [alpha] [beta] [gamma] 并用我试过的所有东西来分隔列表,除了逗号, alpha :: beta :: gamma 在下面的示例中。

    以下是我的完整(编译)代码:

    #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;
    }
    

    这将输出:

    MY_CHAIN: (alpha) (beta) (gamma)
    MY_BRACES: [alpha] [beta] [gamma]
    MY_SCOPES: alpha :: beta :: gamma
    

    我尝试用括号括起逗号分隔的列表,但CAT不会追加 ) _END 。有什么聪明的想法可以扩展到 alpha, beta, gamma ?

    1 回复  |  直到 6 年前
        1
  •  8
  •   unDeadHerbs ehsan    3 年前

    由于逗号对输出很重要,也是一个语法元素,因此需要为输出创建一个替代逗号。

    #define COMMA() ,
    

    我们还需要一些延迟功能,以便 COMMA 不会立即进行评估。

    #define EMPTY()
    #define DEFER(id) id EMPTY()
    

    现在我们可以将两个宏重新定义为

    #define CHAIN_COMMA_1(x) DEFER(COMMA)() x CHAIN_COMMA_2
    #define CHAIN_COMMA_2(x) DEFER(COMMA)() x CHAIN_COMMA_1
    

    但是,您的 SEE 宏也不喜欢放置逗号,因此传递的参数太多会出错。

    您可以通过以下方式看到宏正在正确执行 looking at the output of the preprocessor 使用 -E 选项