1

用 编写递归宏是否合法__VA_OPT__

GCC 和 Clang 似乎不会递归替换,但我不确定它是否是故意的(因为__VA_OPT__支持是最近的)。

C++ 规范(§19.3.1/3: __VA_OPT__):

否则,替换包括扩展内容的结果作为当前类函数宏 在重新扫描和进一步替换之前的替换列表

上面突出显示的部分是否意味着不可能递归?


例如,要添加可变参数宏参数列表:

#define RECURSE(mFIRST, ...) + mFIRST __VA_OPT__(RECURSE(__VA_ARGS__))

int main(int argc, char const* const argv[])
    {
        return 1 RECURSE(2, 3, 4);
        // Expected result: "return 1 + 2 + 3 + 4;"
    }

GCC 和 Clang 都RECURSE在它们的后预处理中生成。

// NOTE: Below is the output from g++ -E
int main(int argc, char const* const argv[])
 {
  return 1 + 2 RECURSE(3, 4);
 }

注意:如果可能的话,可以相当容易地编写更复杂的可变参数宏,例如连接,因为您可以创建自定义__VA_NO_OPT__from __VA_OPT__,它允许您为 1 和 2+ 参数提供完全独立的代码。

4

1 回答 1

2

答案是肯定的!如果您已经可以在 C 中使用递归宏,那么您可以在 C++20 中执行此操作,__VA_OPT__并使某些事情变得更好。

这是您可以做什么的示例(带有说明)FOR_EACH :定义一个宏,将宏应用于一堆参数,并且比您之前必须做的可怕事情要好得多__VA_OPT__

#define PARENS () // Note space before (), so object-like macro

#define EXPAND(arg) EXPAND1(EXPAND1(EXPAND1(EXPAND1(arg))))
#define EXPAND1(arg) EXPAND2(EXPAND2(EXPAND2(EXPAND2(arg))))
#define EXPAND2(arg) EXPAND3(EXPAND3(EXPAND3(EXPAND3(arg))))
#define EXPAND3(arg) EXPAND4(EXPAND4(EXPAND4(EXPAND4(arg))))
#define EXPAND4(arg) arg

#define FOR_EACH(macro, ...)                                    \
  __VA_OPT__(EXPAND(FOR_EACH_HELPER(macro, __VA_ARGS__)))
#define FOR_EACH_HELPER(macro, a1, ...)                         \
  macro(a1)                                                     \
  __VA_OPT__(FOR_EACH_AGAIN PARENS (macro, __VA_ARGS__))
#define FOR_EACH_AGAIN() FOR_EACH_HELPER

FOR_EACH(F, a, b, c, 1, 2, 3)   // => F(a) F(b) F(c) F(1) F(2) F(3)
于 2021-06-07T21:22:29.550 回答