如何在嵌套上下文中通过 __VA_OPT__ 扩展递归宏
How to expand a recursive macro via __VA_OPT__ in a nested context
我已阅读 this article,它说明了如何使用 __VA_OPT__
函数宏来递归扩展宏。我想实现类似的东西,不同之处在于宏是在嵌套上下文中展开的。
输入:
NEST_RECURSIVE(A, B, C)
应该生产(顺序无关紧要):
((( | C) | B) | A)
我的方法是从这篇文章中稍微概括出来的:
#define PARENS ()
#define EXPAND(...) EXPAND4(EXPAND4(EXPAND4(EXPAND4(__VA_ARGS__))))
#define EXPAND4(...) EXPAND3(EXPAND3(EXPAND3(EXPAND3(__VA_ARGS__))))
#define EXPAND3(...) EXPAND2(EXPAND2(EXPAND2(EXPAND2(__VA_ARGS__))))
#define EXPAND2(...) EXPAND1(EXPAND1(EXPAND1(EXPAND1(__VA_ARGS__))))
#define EXPAND1(...) __VA_ARGS__
#define FOR_EACH_R(func, ...) __VA_OPT__(EXPAND(FOR_EACH_HELPER_R(func, __VA_ARGS__)))
#define FOR_EACH_HELPER_R(func, sub, ...) func(__VA_OPT__(FOR_EACH_AGAIN_R PARENS (func, __VA_ARGS__)), sub)
#define FOR_EACH_AGAIN_R() FOR_EACH_HELPER_R
#define MY_FUNC(nested, var) (nested | var)
#define NEST_RECURSIVE(...) FOR_EACH_R(MY_FUNC, __VA_ARGS__)
当前代码产生以下输出:
(FOR_EACH_HELPER_R (MY_FUNC, B, C) | A)
可以看出,扩展不会发生在第一层之后。
我想我必须 EXPAND
去别的地方,但是,我不知道去哪里。
我想要做的事情完全有可能是不可能的,但是,C++20 之前的递归宏扩展方法(利用 PP_NARG
)确实适用于嵌套,所以我会希望新的、更清洁的方法也适用于它!
您的基本 FOR_EACH_R
是正确的,导致问题的原因是在您的 FOR_EACH_HELPER_R
宏中调用了 func
。
您可以通过暂时删除它来验证这一点:
/* ... */
#define FOR_EACH_HELPER_R(func, sub, ...) (__VA_OPT__(FOR_EACH_AGAIN_R PARENS (func, __VA_ARGS__)), sub)
/* ... */
NEST_RECURSIVE(A, B, C)
会导致:
(((, C), B), A)
1。宏观评估的工作原理
宏评估不是很直观,所以我将快速解释对这个答案很重要的 2 个概念:
1.1 function-like 宏求值顺序
示例:
#define FOO() 1
#define BAR() 2
#define BAZ(A, B) MIAU(A, B)
#define MIAU(A, B) B A
BAZ(FOO(), BAR())
当预处理器看到对 BAZ()
的调用时,将发生以下情况:
-
- 参数已完全计算:
FOO()
-> 1
BAR()
-> 2
-
- 计算值代入宏body:
BAZ(1, 2)
-> MIAU(1, 2)
-
- 宏 body 已完全计算 再次
MIAU(1, 2)
-> 2 1
因此参数可能会被求值两次 - 一次是在它们被替换到宏 body 之前,然后是当 body 被求值时。
这也是您可以将宏作为参数传递给其他宏的原因,例如:
#define FOO(fn) fn()
#define BAR() 12
FOO(BAR)
这里会发生以下情况:
-
- 预处理器完全评估参数:
BAR
确实命名了一个宏,但它不是宏调用。所以预处理器不会评估它并将其视为文本:BAR
-
- 代入宏body:
FOO(BAR)
-> BAR()
-
- body评价:
BAR()
-> 12
您的 EXPAND
宏也使用它来重复强制计算表达式。
1.2 不能从自身调用宏
例如:
#define FOO 1 + FOO
FOO
#define BAR 1 + BAZ
#define BAZ BAR
BAR
FOO
会导致 1 + FOO
BAR
会导致 1 + BAR
基本上在预处理器评估给定宏时,例如BAR
,其中(或它调用的宏之一)中任何 BAR
的出现都将被标记为 不要尝试评估它 - 永远 。
所以基本上一旦一个宏看到它自己的名字,它就结束了。
2。为什么您的示例不起作用
让我们来看看你的 FOR_EACH_R
宏的评估:
(为简单起见,我将省略 EXPAND
宏)
- 第一
EXPAND
轮
- 首先我们从
FOR_EACH_HELPER_R(MY_FUNC, A, B, C)
开始
- 代入body:
MY_FUNC(FOR_EACH_AGAIN_R PARENS (MY_FUNC, B, C), A)
- 然后评估 body
- 预处理器看到对
MY_FUNC
的调用,因此将评估两个参数:
FOR_EACH_AGAIN_R PARENS (MY_FUNC, B, C)
变为 FOR_EACH_AGAIN_R () (MY_FUNC, B, C)
(由于 FOR_EACH_AGAIN_R
不是直接调用,因此未进一步评估)
A
-> A
- 代入
MY_FUNC
body:
MY_FUNC((FOR_EACH_AGAIN_R () (MY_FUNC, B, C)), A)
->
(FOR_EACH_AGAIN_R () (MY_FUNC, B, C) | A)
- 评估body:
(FOR_EACH_AGAIN_R () (MY_FUNC, B, C) | A)
->
(FOR_EACH_HELPER_R (MY_FUNC, B, C) | A)
->
预处理器检测到递归(我们在 MY_FUNC
中,它被 FOR_EACH_HELPER_R
调用,我们试图在这里再次调用 FOR_EACH_HELPER_R
)
所以 FOR_EACH_HELPER_R
将被标记为 不要尝试评估这个
另外 MY_FUNC
参数也将被标记(因为我们在 MY_FUNC
)
- 此后每
EXPAND
轮
- 预处理器尝试计算当前表达式:
(FOR_EACH_HELPER_R (MY_FUNC, B, C) | A)
但是 FOR_EACH_HELPER_R
被标记为 不要尝试评估这个 ,因此调用被忽略并且没有任何内容被替换。
-> 你最终得到 (FOR_EACH_HELPER_R (MY_FUNC, B, C) | A)
作为输出
3。如何修复
最大的问题是您将 FOR_EACH_AGAIN_R(...)
作为参数传递给 func
,它将对该部分求值两次(一次作为参数,一次在 body 中),所以预处理器看到递归调用并停止。
您可以通过将 FOR_EACH_AGAIN_R
延迟另一个评估周期来部分修复它,例如:
/* ... */
#define FOR_EACH_HELPER_R(func, sub, ...) func (__VA_OPT__(FOR_EACH_AGAIN_R PARENS (func, __VA_ARGS__)), sub)
#define FOR_EACH_AGAIN_R() FOR_EACH_AGAIN_R_IMPL PARENS
#define FOR_EACH_AGAIN_R_IMPL() FOR_EACH_HELPER_R
/* ... */
这将导致:
(MY_FUNC (MY_FUNC (, C), B) | A)
现在循环已完全展开,但是 MY_FUNC
仍然存在递归问题。
这里的根本问题是 MY_FUNC
的参数之一将包含 MY_FUNC
,例如:
MY_FUNC((FOR_EACH_AGAIN_R PARENS (MY_FUNC, B, C)), A)
因此,一旦预处理器将 MY_FUNC
替换为 MY_FUNC
,该标记将立即标记为 永远不要尝试再次评估它。
所以 MY_FUNC
链在第一次调用后卡住了。
如果不需要递归调用会容易很多,例如:
/* ... */
#define FOR_EACH_HELPER_R(func, sub, ...) __VA_OPT__(FOR_EACH_AGAIN_R PARENS (func, __VA_ARGS__)), func(sub)
/* ... */
#define MY_FUNC(var) (var)
/* ... */
可以正常工作(结果将是 , (C), (B), (A)
)
如果你绝对需要递归调用,那么只有一种方法:
您需要确保MY_FUNC
永远看不到 FOR_EACH_HELPER_R
& MY_FUNC
.
但是鉴于 MY_FUNC
的每次调用都需要前一次调用的结果,您唯一的选择是以这样一种方式构建宏,即一次评估所有 MY_FUNC
调用。
例如您需要以这样的方式构建 FOR_EACH_HELPER_R
,最终您会得到:
MY_FUNC(MY_FUNC(MY_FUNC(, C), B), A)
以便正确评估递归调用。
确保这一点的最简单方法是使用与 FOR_EACH_AGAIN_R
相同的延迟技巧,例如使用一组这样的宏:
#define DELAY6(...) DELAY6_IMPL PARENS __VA_OPT__((__VA_ARGS__))
#define DELAY5(...) DELAY5_IMPL PARENS __VA_OPT__((__VA_ARGS__))
#define DELAY4(...) DELAY4_IMPL PARENS __VA_OPT__((__VA_ARGS__))
#define DELAY3(...) DELAY3_IMPL PARENS __VA_OPT__((__VA_ARGS__))
#define DELAY2(...) DELAY2_IMPL PARENS __VA_OPT__((__VA_ARGS__))
#define DELAY1(...) DELAY1_IMPL PARENS __VA_OPT__((__VA_ARGS__))
#define DELAY0(...) __VA_ARGS__
#define DELAY6_IMPL() DELAY5
#define DELAY5_IMPL() DELAY4
#define DELAY4_IMPL() DELAY3
#define DELAY3_IMPL() DELAY2
#define DELAY2_IMPL() DELAY1
#define DELAY1_IMPL() DELAY0
因此 DELAY6
将延迟 6 次评估,DELAY5
5 次,等等...
然后你可以用它来延迟调用MY_FUNC
,例如:
#define FOR_EACH_R(func, ...) __VA_OPT__(EXPAND(FOR_EACH_HELPER_R(func, DELAY6, __VA_ARGS__)))
#define FOR_EACH_HELPER_R(func, del, sub, ...) del(func) (__VA_OPT__(FOR_EACH_AGAIN_R PARENS (func, del(), __VA_ARGS__)), sub)
请注意,我们将 del()
而不是 del
传递给 FOR_EACH_HELPER_R
的下一次迭代,这将有效地导致下一个较低的 DELAY*
函数被传递(以便所有延迟在一次评估中解决)
使用 NEST_RECURSIVE(A, B, C, D, E, F, G)
这将计算如下:
DELAY5_IMPL () (MY_FUNC) (DELAY5_IMPL () (MY_FUNC) (FOR_EACH_AGAIN_R () (MY_FUNC, DELAY5_IMPL () , C, D, E, F, G), B), A)
->
DELAY4_IMPL () (MY_FUNC) (DELAY4_IMPL () (MY_FUNC) (DELAY4_IMPL () (MY_FUNC) (FOR_EACH_AGAIN_R () (MY_FUNC, DELAY4_IMPL () , D, E, F, G), C), B), A)
->
DELAY3_IMPL () (MY_FUNC) (DELAY3_IMPL () (MY_FUNC) (DELAY3_IMPL () (MY_FUNC) (DELAY3_IMPL () (MY_FUNC) (FOR_EACH_AGAIN_R () (MY_FUNC, DELAY3_IMPL () , E, F, G), D), C), B), A)
->
DELAY2_IMPL () (MY_FUNC) (DELAY2_IMPL () (MY_FUNC) (DELAY2_IMPL () (MY_FUNC) (DELAY2_IMPL () (MY_FUNC) (DELAY2_IMPL () (MY_FUNC) (FOR_EACH_AGAIN_R () (MY_FUNC, DELAY2_IMPL () , F, G), E), D), C), B), A)
->
DELAY1_IMPL () (MY_FUNC) (DELAY1_IMPL () (MY_FUNC) (DELAY1_IMPL () (MY_FUNC) (DELAY1_IMPL () (MY_FUNC) (DELAY1_IMPL () (MY_FUNC) (DELAY1_IMPL () (MY_FUNC) (FOR_EACH_AGAIN_R () (MY_FUNC, DELAY1_IMPL () , G), F), E), D), C), B), A)
->
((((((( | G) | F) | E) | D) | C) | B) | A)
请注意 MY_FUNC
直到最后一轮评估才被调用 - 这基本上确保所有 MY_FUNC 调用都被立即评估,并且我们不会遇到递归宏调用的任何问题.
你必须定义很多 DELAY_
宏才能工作(FOR_EACH_R
的每个附加参数需要 1 个延迟宏)
完整代码示例:godbolt
#define PARENS ()
#define EXPAND(...) EXPAND4(EXPAND4(EXPAND4(EXPAND4(__VA_ARGS__))))
#define EXPAND4(...) EXPAND3(EXPAND3(EXPAND3(EXPAND3(__VA_ARGS__))))
#define EXPAND3(...) EXPAND2(EXPAND2(EXPAND2(EXPAND2(__VA_ARGS__))))
#define EXPAND2(...) EXPAND1(EXPAND1(EXPAND1(EXPAND1(__VA_ARGS__))))
#define EXPAND1(...) __VA_ARGS__
#define DELAY6(...) DELAY6_IMPL PARENS __VA_OPT__((__VA_ARGS__))
#define DELAY5(...) DELAY5_IMPL PARENS __VA_OPT__((__VA_ARGS__))
#define DELAY4(...) DELAY4_IMPL PARENS __VA_OPT__((__VA_ARGS__))
#define DELAY3(...) DELAY3_IMPL PARENS __VA_OPT__((__VA_ARGS__))
#define DELAY2(...) DELAY2_IMPL PARENS __VA_OPT__((__VA_ARGS__))
#define DELAY1(...) DELAY1_IMPL PARENS __VA_OPT__((__VA_ARGS__))
#define DELAY0(...) __VA_ARGS__
#define DELAY6_IMPL() DELAY5
#define DELAY5_IMPL() DELAY4
#define DELAY4_IMPL() DELAY3
#define DELAY3_IMPL() DELAY2
#define DELAY2_IMPL() DELAY1
#define DELAY1_IMPL() DELAY0
#define FOR_EACH_R(func, ...) __VA_OPT__(EXPAND(FOR_EACH_HELPER_R(func, DELAY6, __VA_ARGS__)))
#define FOR_EACH_HELPER_R(func, del, sub, ...) del(func) (__VA_OPT__(FOR_EACH_AGAIN_R PARENS (func, del(), __VA_ARGS__)), sub)
#define FOR_EACH_AGAIN_R() FOR_EACH_HELPER_R
#define MY_FUNC(nested, var) (nested | var)
#define NEST_RECURSIVE(...) FOR_EACH_R(MY_FUNC, __VA_ARGS__)
NEST_RECURSIVE(A, B, C, D, E, F, G)
4。可能更好的方法
4.1 简单宏链
上述解决方案需要很好地理解如何计算宏才能理解发生了什么。您也可以通过定义一堆宏来选择更简单的方法,例如 boost does for example
例如:
#define FOR_EACH_ERROR()
#define FOR_EACH_R(fn, ...) __VA_OPT__(FOR_EACH_R_IMPL_0(fn, __VA_ARGS__))
#define FOR_EACH_R_IMPL_0(fn, el, ...) fn(__VA_OPT__(FOR_EACH_R_IMPL_1(fn, __VA_ARGS__)), el)
#define FOR_EACH_R_IMPL_1(fn, el, ...) fn(__VA_OPT__(FOR_EACH_R_IMPL_2(fn, __VA_ARGS__)), el)
#define FOR_EACH_R_IMPL_2(fn, el, ...) fn(__VA_OPT__(FOR_EACH_R_IMPL_3(fn, __VA_ARGS__)), el)
#define FOR_EACH_R_IMPL_3(fn, el, ...) fn(__VA_OPT__(FOR_EACH_R_IMPL_4(fn, __VA_ARGS__)), el)
#define FOR_EACH_R_IMPL_4(fn, el, ...) fn(__VA_OPT__(FOR_EACH_R_IMPL_5(fn, __VA_ARGS__)), el)
#define FOR_EACH_R_IMPL_5(fn, el, ...) fn(__VA_OPT__(FOR_EACH_R_IMPL_6(fn, __VA_ARGS__)), el)
#define FOR_EACH_R_IMPL_6(fn, el, ...) fn(__VA_OPT__(FOR_EACH_R_IMPL_7(fn, __VA_ARGS__)), el)
#define FOR_EACH_R_IMPL_7(fn, el, ...) fn(__VA_OPT__(FOR_EACH_R_IMPL_8(fn, __VA_ARGS__)), el)
#define FOR_EACH_R_IMPL_8(fn, el, ...) fn(__VA_OPT__(FOR_EACH_R_IMPL_9(fn, __VA_ARGS__)), el)
#define FOR_EACH_R_IMPL_9(fn, el, ...) fn(__VA_OPT__(FOR_EACH_R_IMPL_10(fn, __VA_ARGS__)), el)
#define FOR_EACH_R_IMPL_10(...) FOR_EACH_ERROR("Shenanigans!")
#define MY_FUNC(nested, var) (nested | var)
#define NEST_RECURSIVE(...) FOR_EACH_R(MY_FUNC, __VA_ARGS__)
NEST_RECURSIVE(A, B, C, D, E, F, G)
这更容易理解,也很容易扩展(只需添加更多宏)
4.2递归左折叠
如果你想要一个递归版本来减少你需要写的行数,你可以通过使用左折叠来实现,例如:
// Recursive Left Fold
#define FOR_EACH_L(fn, ...) __VA_OPT__(FOR_EACH_APPLY0(FOR_EACH_RESULT, FOR_EACH_L_4(fn,,__VA_ARGS__)))
#define FOR_EACH_L_4(fn, res, ...) FOR_EACH_APPLY4(FOR_EACH_L_3, FOR_EACH_APPLY4(FOR_EACH_L_3, FOR_EACH_APPLY4(FOR_EACH_L_3, fn, res __VA_OPT__(, __VA_ARGS__))))
#define FOR_EACH_L_3(fn, res, ...) FOR_EACH_APPLY3(FOR_EACH_L_2, FOR_EACH_APPLY3(FOR_EACH_L_2, FOR_EACH_APPLY3(FOR_EACH_L_2, fn, res __VA_OPT__(, __VA_ARGS__))))
#define FOR_EACH_L_2(fn, res, ...) FOR_EACH_APPLY2(FOR_EACH_L_1, FOR_EACH_APPLY2(FOR_EACH_L_1, FOR_EACH_APPLY2(FOR_EACH_L_1, fn, res __VA_OPT__(, __VA_ARGS__))))
#define FOR_EACH_L_1(fn, res, ...) FOR_EACH_APPLY1(FOR_EACH_L_0, FOR_EACH_APPLY1(FOR_EACH_L_0, FOR_EACH_APPLY1(FOR_EACH_L_0, fn, res __VA_OPT__(, __VA_ARGS__))))
#define FOR_EACH_L_0(fn, res, ...) fn, FOR_EACH_FIRST(__VA_OPT__(fn(res, FOR_EACH_FIRST(__VA_ARGS__)), ) res) __VA_OPT__(FOR_EACH_TAIL(__VA_ARGS__))
#define FOR_EACH_APPLY4(fn, ...) fn(__VA_ARGS__)
#define FOR_EACH_APPLY3(fn, ...) fn(__VA_ARGS__)
#define FOR_EACH_APPLY2(fn, ...) fn(__VA_ARGS__)
#define FOR_EACH_APPLY1(fn, ...) fn(__VA_ARGS__)
#define FOR_EACH_APPLY0(fn, ...) fn(__VA_ARGS__)
#define FOR_EACH_FIRST(el, ...) el
#define FOR_EACH_TAIL(el, ...) __VA_OPT__(, __VA_ARGS__)
#define FOR_EACH_RESULT(fn, res, ...) res
Left-folds比right-folds更容易实现,因为获取__VA_ARGS__
的第一个元素比获取最后一个元素容易很多(上面的FOR_EACH_FIRST
例如)。
上面提供的版本最多可以处理 81 个参数,如果您需要更多,只需创建更多版本的 FOR_EACH_L_*
和 FOR_EACH_APPLY*
宏。 (这些宏中每增加一个,它可以处理的参数的最大数量就会增加三倍)
尽管如此,您确实需要以相反的顺序提供参数,因为它是左折叠,例如:
NEST_RECURSIVE(A, B, C, D, E, F, G)
// would result in ((((((( | A) | B) | C) | D) | E) | F) | G)
如果您需要右折叠,您可以通过反转参数然后调用我们在上面创建的左折叠变体来实现它。
例如:
// Reverse args
#define PARENS ()
#define EXPAND(...) EXPAND4(EXPAND4(EXPAND4(EXPAND4(__VA_ARGS__))))
#define EXPAND4(...) EXPAND3(EXPAND3(EXPAND3(EXPAND3(__VA_ARGS__))))
#define EXPAND3(...) EXPAND2(EXPAND2(EXPAND2(EXPAND2(__VA_ARGS__))))
#define EXPAND2(...) EXPAND1(EXPAND1(EXPAND1(EXPAND1(__VA_ARGS__))))
#define EXPAND1(...) __VA_ARGS__
#define REVERSE(...) __VA_OPT__(EXPAND(REVERSE_HELPER(__VA_ARGS__)))
#define REVERSE_HELPER(el, ...) __VA_OPT__(REVERSE_AGAIN PARENS (__VA_ARGS__), ) el
#define REVERSE_AGAIN() REVERSE_HELPER
(这也只适用于最多 81 个参数,您可以添加更多 EXPAND*
宏来增加它可以处理的参数数量)
示例:
REVERSE(A, B, C, D, E, F, G)
// would result in G, F, E, D, C, B, A
然后你可以像这样实现正确的折叠:
// Right fold
#define FOR_EACH_R(fn, ...) __VA_OPT__(FOR_EACH_R_APPLY(FOR_EACH_L, fn, REVERSE(__VA_ARGS__)))
#define FOR_EACH_R_APPLY(fn, ...) fn(__VA_ARGS__)
这最终会为您提供预期的结果(最多 81 个参数),例如:
NEST_RECURSIVE(A, B, C, D, E, F, G)
// would result in: ((((((( | G) | F) | E) | D) | C) | B) | A)
完整代码:godbolt
// Reverse args
#define PARENS ()
#define EXPAND(...) EXPAND4(EXPAND4(EXPAND4(EXPAND4(__VA_ARGS__))))
#define EXPAND4(...) EXPAND3(EXPAND3(EXPAND3(EXPAND3(__VA_ARGS__))))
#define EXPAND3(...) EXPAND2(EXPAND2(EXPAND2(EXPAND2(__VA_ARGS__))))
#define EXPAND2(...) EXPAND1(EXPAND1(EXPAND1(EXPAND1(__VA_ARGS__))))
#define EXPAND1(...) __VA_ARGS__
#define REVERSE(...) __VA_OPT__(EXPAND(REVERSE_HELPER(__VA_ARGS__)))
#define REVERSE_HELPER(el, ...) __VA_OPT__(REVERSE_AGAIN PARENS (__VA_ARGS__), ) el
#define REVERSE_AGAIN() REVERSE_HELPER
// Recursive Left Fold
#define FOR_EACH_L(fn, ...) __VA_OPT__(FOR_EACH_APPLY0(FOR_EACH_RESULT, FOR_EACH_L_4(fn,,__VA_ARGS__)))
#define FOR_EACH_L_4(fn, res, ...) FOR_EACH_APPLY4(FOR_EACH_L_3, FOR_EACH_APPLY4(FOR_EACH_L_3, FOR_EACH_APPLY4(FOR_EACH_L_3, fn, res __VA_OPT__(, __VA_ARGS__))))
#define FOR_EACH_L_3(fn, res, ...) FOR_EACH_APPLY3(FOR_EACH_L_2, FOR_EACH_APPLY3(FOR_EACH_L_2, FOR_EACH_APPLY3(FOR_EACH_L_2, fn, res __VA_OPT__(, __VA_ARGS__))))
#define FOR_EACH_L_2(fn, res, ...) FOR_EACH_APPLY2(FOR_EACH_L_1, FOR_EACH_APPLY2(FOR_EACH_L_1, FOR_EACH_APPLY2(FOR_EACH_L_1, fn, res __VA_OPT__(, __VA_ARGS__))))
#define FOR_EACH_L_1(fn, res, ...) FOR_EACH_APPLY1(FOR_EACH_L_0, FOR_EACH_APPLY1(FOR_EACH_L_0, FOR_EACH_APPLY1(FOR_EACH_L_0, fn, res __VA_OPT__(, __VA_ARGS__))))
#define FOR_EACH_L_0(fn, res, ...) fn, FOR_EACH_FIRST(__VA_OPT__(fn(res, FOR_EACH_FIRST(__VA_ARGS__)), ) res) __VA_OPT__(FOR_EACH_TAIL(__VA_ARGS__))
#define FOR_EACH_APPLY4(fn, ...) fn(__VA_ARGS__)
#define FOR_EACH_APPLY3(fn, ...) fn(__VA_ARGS__)
#define FOR_EACH_APPLY2(fn, ...) fn(__VA_ARGS__)
#define FOR_EACH_APPLY1(fn, ...) fn(__VA_ARGS__)
#define FOR_EACH_APPLY0(fn, ...) fn(__VA_ARGS__)
#define FOR_EACH_FIRST(el, ...) el
#define FOR_EACH_TAIL(el, ...) __VA_OPT__(, __VA_ARGS__)
#define FOR_EACH_RESULT(fn, res, ...) res
// Right fold
#define FOR_EACH_R(fn, ...) __VA_OPT__(FOR_EACH_R_APPLY(FOR_EACH_L, fn, REVERSE(__VA_ARGS__)))
#define FOR_EACH_R_APPLY(fn, ...) fn(__VA_ARGS__)
// For testing
#define MY_FUNC(nested, var) (nested | var)
#define NEST_RECURSIVE(...) FOR_EACH_R(MY_FUNC, __VA_ARGS__)
NEST_RECURSIVE(A, B, C, D, E, F, G)
我已阅读 this article,它说明了如何使用 __VA_OPT__
函数宏来递归扩展宏。我想实现类似的东西,不同之处在于宏是在嵌套上下文中展开的。
输入:
NEST_RECURSIVE(A, B, C)
应该生产(顺序无关紧要):
((( | C) | B) | A)
我的方法是从这篇文章中稍微概括出来的:
#define PARENS ()
#define EXPAND(...) EXPAND4(EXPAND4(EXPAND4(EXPAND4(__VA_ARGS__))))
#define EXPAND4(...) EXPAND3(EXPAND3(EXPAND3(EXPAND3(__VA_ARGS__))))
#define EXPAND3(...) EXPAND2(EXPAND2(EXPAND2(EXPAND2(__VA_ARGS__))))
#define EXPAND2(...) EXPAND1(EXPAND1(EXPAND1(EXPAND1(__VA_ARGS__))))
#define EXPAND1(...) __VA_ARGS__
#define FOR_EACH_R(func, ...) __VA_OPT__(EXPAND(FOR_EACH_HELPER_R(func, __VA_ARGS__)))
#define FOR_EACH_HELPER_R(func, sub, ...) func(__VA_OPT__(FOR_EACH_AGAIN_R PARENS (func, __VA_ARGS__)), sub)
#define FOR_EACH_AGAIN_R() FOR_EACH_HELPER_R
#define MY_FUNC(nested, var) (nested | var)
#define NEST_RECURSIVE(...) FOR_EACH_R(MY_FUNC, __VA_ARGS__)
当前代码产生以下输出:
(FOR_EACH_HELPER_R (MY_FUNC, B, C) | A)
可以看出,扩展不会发生在第一层之后。
我想我必须 EXPAND
去别的地方,但是,我不知道去哪里。
我想要做的事情完全有可能是不可能的,但是,C++20 之前的递归宏扩展方法(利用 PP_NARG
)确实适用于嵌套,所以我会希望新的、更清洁的方法也适用于它!
您的基本 FOR_EACH_R
是正确的,导致问题的原因是在您的 FOR_EACH_HELPER_R
宏中调用了 func
。
您可以通过暂时删除它来验证这一点:
/* ... */
#define FOR_EACH_HELPER_R(func, sub, ...) (__VA_OPT__(FOR_EACH_AGAIN_R PARENS (func, __VA_ARGS__)), sub)
/* ... */
NEST_RECURSIVE(A, B, C)
会导致:
(((, C), B), A)
1。宏观评估的工作原理
宏评估不是很直观,所以我将快速解释对这个答案很重要的 2 个概念:
1.1 function-like 宏求值顺序
示例:
#define FOO() 1
#define BAR() 2
#define BAZ(A, B) MIAU(A, B)
#define MIAU(A, B) B A
BAZ(FOO(), BAR())
当预处理器看到对 BAZ()
的调用时,将发生以下情况:
-
- 参数已完全计算:
FOO()
-> 1BAR()
-> 2
-
- 计算值代入宏body:
BAZ(1, 2)
->MIAU(1, 2)
-
- 宏 body 已完全计算 再次
MIAU(1, 2)
->2 1
因此参数可能会被求值两次 - 一次是在它们被替换到宏 body 之前,然后是当 body 被求值时。
这也是您可以将宏作为参数传递给其他宏的原因,例如:
#define FOO(fn) fn()
#define BAR() 12
FOO(BAR)
这里会发生以下情况:
-
- 预处理器完全评估参数:
BAR
确实命名了一个宏,但它不是宏调用。所以预处理器不会评估它并将其视为文本:BAR
- 预处理器完全评估参数:
-
- 代入宏body:
FOO(BAR)
->BAR()
- 代入宏body:
-
- body评价:
BAR()
->12
- body评价:
您的 EXPAND
宏也使用它来重复强制计算表达式。
1.2 不能从自身调用宏
例如:
#define FOO 1 + FOO
FOO
#define BAR 1 + BAZ
#define BAZ BAR
BAR
FOO
会导致1 + FOO
BAR
会导致1 + BAR
基本上在预处理器评估给定宏时,例如BAR
,其中(或它调用的宏之一)中任何 BAR
的出现都将被标记为 不要尝试评估它 - 永远 。
所以基本上一旦一个宏看到它自己的名字,它就结束了。
2。为什么您的示例不起作用
让我们来看看你的 FOR_EACH_R
宏的评估:
(为简单起见,我将省略 EXPAND
宏)
- 第一
EXPAND
轮
- 首先我们从
FOR_EACH_HELPER_R(MY_FUNC, A, B, C)
开始
- 代入body:
MY_FUNC(FOR_EACH_AGAIN_R PARENS (MY_FUNC, B, C), A)
- 然后评估 body
- 预处理器看到对
MY_FUNC
的调用,因此将评估两个参数:FOR_EACH_AGAIN_R PARENS (MY_FUNC, B, C)
变为FOR_EACH_AGAIN_R () (MY_FUNC, B, C)
(由于FOR_EACH_AGAIN_R
不是直接调用,因此未进一步评估)A
->A
- 预处理器看到对
- 代入
MY_FUNC
body:
MY_FUNC((FOR_EACH_AGAIN_R () (MY_FUNC, B, C)), A)
->
(FOR_EACH_AGAIN_R () (MY_FUNC, B, C) | A)
- 评估body:
(FOR_EACH_AGAIN_R () (MY_FUNC, B, C) | A)
->
(FOR_EACH_HELPER_R (MY_FUNC, B, C) | A)
->
预处理器检测到递归(我们在MY_FUNC
中,它被FOR_EACH_HELPER_R
调用,我们试图在这里再次调用FOR_EACH_HELPER_R
)
所以FOR_EACH_HELPER_R
将被标记为 不要尝试评估这个
另外MY_FUNC
参数也将被标记(因为我们在MY_FUNC
)
- 此后每
EXPAND
轮
- 预处理器尝试计算当前表达式:
(FOR_EACH_HELPER_R (MY_FUNC, B, C) | A)
但是FOR_EACH_HELPER_R
被标记为 不要尝试评估这个 ,因此调用被忽略并且没有任何内容被替换。
-> 你最终得到 (FOR_EACH_HELPER_R (MY_FUNC, B, C) | A)
作为输出
3。如何修复
最大的问题是您将 FOR_EACH_AGAIN_R(...)
作为参数传递给 func
,它将对该部分求值两次(一次作为参数,一次在 body 中),所以预处理器看到递归调用并停止。
您可以通过将 FOR_EACH_AGAIN_R
延迟另一个评估周期来部分修复它,例如:
/* ... */
#define FOR_EACH_HELPER_R(func, sub, ...) func (__VA_OPT__(FOR_EACH_AGAIN_R PARENS (func, __VA_ARGS__)), sub)
#define FOR_EACH_AGAIN_R() FOR_EACH_AGAIN_R_IMPL PARENS
#define FOR_EACH_AGAIN_R_IMPL() FOR_EACH_HELPER_R
/* ... */
这将导致:
(MY_FUNC (MY_FUNC (, C), B) | A)
现在循环已完全展开,但是 MY_FUNC
仍然存在递归问题。
这里的根本问题是 MY_FUNC
的参数之一将包含 MY_FUNC
,例如:
MY_FUNC((FOR_EACH_AGAIN_R PARENS (MY_FUNC, B, C)), A)
因此,一旦预处理器将 MY_FUNC
替换为 MY_FUNC
,该标记将立即标记为 永远不要尝试再次评估它。
所以 MY_FUNC
链在第一次调用后卡住了。
如果不需要递归调用会容易很多,例如:
/* ... */
#define FOR_EACH_HELPER_R(func, sub, ...) __VA_OPT__(FOR_EACH_AGAIN_R PARENS (func, __VA_ARGS__)), func(sub)
/* ... */
#define MY_FUNC(var) (var)
/* ... */
可以正常工作(结果将是 , (C), (B), (A)
)
如果你绝对需要递归调用,那么只有一种方法:
您需要确保MY_FUNC
永远看不到 FOR_EACH_HELPER_R
& MY_FUNC
.
但是鉴于 MY_FUNC
的每次调用都需要前一次调用的结果,您唯一的选择是以这样一种方式构建宏,即一次评估所有 MY_FUNC
调用。
例如您需要以这样的方式构建 FOR_EACH_HELPER_R
,最终您会得到:
MY_FUNC(MY_FUNC(MY_FUNC(, C), B), A)
以便正确评估递归调用。
确保这一点的最简单方法是使用与 FOR_EACH_AGAIN_R
相同的延迟技巧,例如使用一组这样的宏:
#define DELAY6(...) DELAY6_IMPL PARENS __VA_OPT__((__VA_ARGS__))
#define DELAY5(...) DELAY5_IMPL PARENS __VA_OPT__((__VA_ARGS__))
#define DELAY4(...) DELAY4_IMPL PARENS __VA_OPT__((__VA_ARGS__))
#define DELAY3(...) DELAY3_IMPL PARENS __VA_OPT__((__VA_ARGS__))
#define DELAY2(...) DELAY2_IMPL PARENS __VA_OPT__((__VA_ARGS__))
#define DELAY1(...) DELAY1_IMPL PARENS __VA_OPT__((__VA_ARGS__))
#define DELAY0(...) __VA_ARGS__
#define DELAY6_IMPL() DELAY5
#define DELAY5_IMPL() DELAY4
#define DELAY4_IMPL() DELAY3
#define DELAY3_IMPL() DELAY2
#define DELAY2_IMPL() DELAY1
#define DELAY1_IMPL() DELAY0
因此 DELAY6
将延迟 6 次评估,DELAY5
5 次,等等...
然后你可以用它来延迟调用MY_FUNC
,例如:
#define FOR_EACH_R(func, ...) __VA_OPT__(EXPAND(FOR_EACH_HELPER_R(func, DELAY6, __VA_ARGS__)))
#define FOR_EACH_HELPER_R(func, del, sub, ...) del(func) (__VA_OPT__(FOR_EACH_AGAIN_R PARENS (func, del(), __VA_ARGS__)), sub)
请注意,我们将 del()
而不是 del
传递给 FOR_EACH_HELPER_R
的下一次迭代,这将有效地导致下一个较低的 DELAY*
函数被传递(以便所有延迟在一次评估中解决)
使用 NEST_RECURSIVE(A, B, C, D, E, F, G)
这将计算如下:
DELAY5_IMPL () (MY_FUNC) (DELAY5_IMPL () (MY_FUNC) (FOR_EACH_AGAIN_R () (MY_FUNC, DELAY5_IMPL () , C, D, E, F, G), B), A)
->
DELAY4_IMPL () (MY_FUNC) (DELAY4_IMPL () (MY_FUNC) (DELAY4_IMPL () (MY_FUNC) (FOR_EACH_AGAIN_R () (MY_FUNC, DELAY4_IMPL () , D, E, F, G), C), B), A)
->
DELAY3_IMPL () (MY_FUNC) (DELAY3_IMPL () (MY_FUNC) (DELAY3_IMPL () (MY_FUNC) (DELAY3_IMPL () (MY_FUNC) (FOR_EACH_AGAIN_R () (MY_FUNC, DELAY3_IMPL () , E, F, G), D), C), B), A)
->
DELAY2_IMPL () (MY_FUNC) (DELAY2_IMPL () (MY_FUNC) (DELAY2_IMPL () (MY_FUNC) (DELAY2_IMPL () (MY_FUNC) (DELAY2_IMPL () (MY_FUNC) (FOR_EACH_AGAIN_R () (MY_FUNC, DELAY2_IMPL () , F, G), E), D), C), B), A)
->
DELAY1_IMPL () (MY_FUNC) (DELAY1_IMPL () (MY_FUNC) (DELAY1_IMPL () (MY_FUNC) (DELAY1_IMPL () (MY_FUNC) (DELAY1_IMPL () (MY_FUNC) (DELAY1_IMPL () (MY_FUNC) (FOR_EACH_AGAIN_R () (MY_FUNC, DELAY1_IMPL () , G), F), E), D), C), B), A)
->
((((((( | G) | F) | E) | D) | C) | B) | A)
请注意 MY_FUNC
直到最后一轮评估才被调用 - 这基本上确保所有 MY_FUNC 调用都被立即评估,并且我们不会遇到递归宏调用的任何问题.
你必须定义很多 DELAY_
宏才能工作(FOR_EACH_R
的每个附加参数需要 1 个延迟宏)
完整代码示例:godbolt
#define PARENS ()
#define EXPAND(...) EXPAND4(EXPAND4(EXPAND4(EXPAND4(__VA_ARGS__))))
#define EXPAND4(...) EXPAND3(EXPAND3(EXPAND3(EXPAND3(__VA_ARGS__))))
#define EXPAND3(...) EXPAND2(EXPAND2(EXPAND2(EXPAND2(__VA_ARGS__))))
#define EXPAND2(...) EXPAND1(EXPAND1(EXPAND1(EXPAND1(__VA_ARGS__))))
#define EXPAND1(...) __VA_ARGS__
#define DELAY6(...) DELAY6_IMPL PARENS __VA_OPT__((__VA_ARGS__))
#define DELAY5(...) DELAY5_IMPL PARENS __VA_OPT__((__VA_ARGS__))
#define DELAY4(...) DELAY4_IMPL PARENS __VA_OPT__((__VA_ARGS__))
#define DELAY3(...) DELAY3_IMPL PARENS __VA_OPT__((__VA_ARGS__))
#define DELAY2(...) DELAY2_IMPL PARENS __VA_OPT__((__VA_ARGS__))
#define DELAY1(...) DELAY1_IMPL PARENS __VA_OPT__((__VA_ARGS__))
#define DELAY0(...) __VA_ARGS__
#define DELAY6_IMPL() DELAY5
#define DELAY5_IMPL() DELAY4
#define DELAY4_IMPL() DELAY3
#define DELAY3_IMPL() DELAY2
#define DELAY2_IMPL() DELAY1
#define DELAY1_IMPL() DELAY0
#define FOR_EACH_R(func, ...) __VA_OPT__(EXPAND(FOR_EACH_HELPER_R(func, DELAY6, __VA_ARGS__)))
#define FOR_EACH_HELPER_R(func, del, sub, ...) del(func) (__VA_OPT__(FOR_EACH_AGAIN_R PARENS (func, del(), __VA_ARGS__)), sub)
#define FOR_EACH_AGAIN_R() FOR_EACH_HELPER_R
#define MY_FUNC(nested, var) (nested | var)
#define NEST_RECURSIVE(...) FOR_EACH_R(MY_FUNC, __VA_ARGS__)
NEST_RECURSIVE(A, B, C, D, E, F, G)
4。可能更好的方法
4.1 简单宏链
上述解决方案需要很好地理解如何计算宏才能理解发生了什么。您也可以通过定义一堆宏来选择更简单的方法,例如 boost does for example
例如:
#define FOR_EACH_ERROR()
#define FOR_EACH_R(fn, ...) __VA_OPT__(FOR_EACH_R_IMPL_0(fn, __VA_ARGS__))
#define FOR_EACH_R_IMPL_0(fn, el, ...) fn(__VA_OPT__(FOR_EACH_R_IMPL_1(fn, __VA_ARGS__)), el)
#define FOR_EACH_R_IMPL_1(fn, el, ...) fn(__VA_OPT__(FOR_EACH_R_IMPL_2(fn, __VA_ARGS__)), el)
#define FOR_EACH_R_IMPL_2(fn, el, ...) fn(__VA_OPT__(FOR_EACH_R_IMPL_3(fn, __VA_ARGS__)), el)
#define FOR_EACH_R_IMPL_3(fn, el, ...) fn(__VA_OPT__(FOR_EACH_R_IMPL_4(fn, __VA_ARGS__)), el)
#define FOR_EACH_R_IMPL_4(fn, el, ...) fn(__VA_OPT__(FOR_EACH_R_IMPL_5(fn, __VA_ARGS__)), el)
#define FOR_EACH_R_IMPL_5(fn, el, ...) fn(__VA_OPT__(FOR_EACH_R_IMPL_6(fn, __VA_ARGS__)), el)
#define FOR_EACH_R_IMPL_6(fn, el, ...) fn(__VA_OPT__(FOR_EACH_R_IMPL_7(fn, __VA_ARGS__)), el)
#define FOR_EACH_R_IMPL_7(fn, el, ...) fn(__VA_OPT__(FOR_EACH_R_IMPL_8(fn, __VA_ARGS__)), el)
#define FOR_EACH_R_IMPL_8(fn, el, ...) fn(__VA_OPT__(FOR_EACH_R_IMPL_9(fn, __VA_ARGS__)), el)
#define FOR_EACH_R_IMPL_9(fn, el, ...) fn(__VA_OPT__(FOR_EACH_R_IMPL_10(fn, __VA_ARGS__)), el)
#define FOR_EACH_R_IMPL_10(...) FOR_EACH_ERROR("Shenanigans!")
#define MY_FUNC(nested, var) (nested | var)
#define NEST_RECURSIVE(...) FOR_EACH_R(MY_FUNC, __VA_ARGS__)
NEST_RECURSIVE(A, B, C, D, E, F, G)
这更容易理解,也很容易扩展(只需添加更多宏)
4.2递归左折叠
如果你想要一个递归版本来减少你需要写的行数,你可以通过使用左折叠来实现,例如:
// Recursive Left Fold
#define FOR_EACH_L(fn, ...) __VA_OPT__(FOR_EACH_APPLY0(FOR_EACH_RESULT, FOR_EACH_L_4(fn,,__VA_ARGS__)))
#define FOR_EACH_L_4(fn, res, ...) FOR_EACH_APPLY4(FOR_EACH_L_3, FOR_EACH_APPLY4(FOR_EACH_L_3, FOR_EACH_APPLY4(FOR_EACH_L_3, fn, res __VA_OPT__(, __VA_ARGS__))))
#define FOR_EACH_L_3(fn, res, ...) FOR_EACH_APPLY3(FOR_EACH_L_2, FOR_EACH_APPLY3(FOR_EACH_L_2, FOR_EACH_APPLY3(FOR_EACH_L_2, fn, res __VA_OPT__(, __VA_ARGS__))))
#define FOR_EACH_L_2(fn, res, ...) FOR_EACH_APPLY2(FOR_EACH_L_1, FOR_EACH_APPLY2(FOR_EACH_L_1, FOR_EACH_APPLY2(FOR_EACH_L_1, fn, res __VA_OPT__(, __VA_ARGS__))))
#define FOR_EACH_L_1(fn, res, ...) FOR_EACH_APPLY1(FOR_EACH_L_0, FOR_EACH_APPLY1(FOR_EACH_L_0, FOR_EACH_APPLY1(FOR_EACH_L_0, fn, res __VA_OPT__(, __VA_ARGS__))))
#define FOR_EACH_L_0(fn, res, ...) fn, FOR_EACH_FIRST(__VA_OPT__(fn(res, FOR_EACH_FIRST(__VA_ARGS__)), ) res) __VA_OPT__(FOR_EACH_TAIL(__VA_ARGS__))
#define FOR_EACH_APPLY4(fn, ...) fn(__VA_ARGS__)
#define FOR_EACH_APPLY3(fn, ...) fn(__VA_ARGS__)
#define FOR_EACH_APPLY2(fn, ...) fn(__VA_ARGS__)
#define FOR_EACH_APPLY1(fn, ...) fn(__VA_ARGS__)
#define FOR_EACH_APPLY0(fn, ...) fn(__VA_ARGS__)
#define FOR_EACH_FIRST(el, ...) el
#define FOR_EACH_TAIL(el, ...) __VA_OPT__(, __VA_ARGS__)
#define FOR_EACH_RESULT(fn, res, ...) res
Left-folds比right-folds更容易实现,因为获取__VA_ARGS__
的第一个元素比获取最后一个元素容易很多(上面的FOR_EACH_FIRST
例如)。
上面提供的版本最多可以处理 81 个参数,如果您需要更多,只需创建更多版本的 FOR_EACH_L_*
和 FOR_EACH_APPLY*
宏。 (这些宏中每增加一个,它可以处理的参数的最大数量就会增加三倍)
尽管如此,您确实需要以相反的顺序提供参数,因为它是左折叠,例如:
NEST_RECURSIVE(A, B, C, D, E, F, G)
// would result in ((((((( | A) | B) | C) | D) | E) | F) | G)
如果您需要右折叠,您可以通过反转参数然后调用我们在上面创建的左折叠变体来实现它。
例如:
// Reverse args
#define PARENS ()
#define EXPAND(...) EXPAND4(EXPAND4(EXPAND4(EXPAND4(__VA_ARGS__))))
#define EXPAND4(...) EXPAND3(EXPAND3(EXPAND3(EXPAND3(__VA_ARGS__))))
#define EXPAND3(...) EXPAND2(EXPAND2(EXPAND2(EXPAND2(__VA_ARGS__))))
#define EXPAND2(...) EXPAND1(EXPAND1(EXPAND1(EXPAND1(__VA_ARGS__))))
#define EXPAND1(...) __VA_ARGS__
#define REVERSE(...) __VA_OPT__(EXPAND(REVERSE_HELPER(__VA_ARGS__)))
#define REVERSE_HELPER(el, ...) __VA_OPT__(REVERSE_AGAIN PARENS (__VA_ARGS__), ) el
#define REVERSE_AGAIN() REVERSE_HELPER
(这也只适用于最多 81 个参数,您可以添加更多 EXPAND*
宏来增加它可以处理的参数数量)
示例:
REVERSE(A, B, C, D, E, F, G)
// would result in G, F, E, D, C, B, A
然后你可以像这样实现正确的折叠:
// Right fold
#define FOR_EACH_R(fn, ...) __VA_OPT__(FOR_EACH_R_APPLY(FOR_EACH_L, fn, REVERSE(__VA_ARGS__)))
#define FOR_EACH_R_APPLY(fn, ...) fn(__VA_ARGS__)
这最终会为您提供预期的结果(最多 81 个参数),例如:
NEST_RECURSIVE(A, B, C, D, E, F, G)
// would result in: ((((((( | G) | F) | E) | D) | C) | B) | A)
完整代码:godbolt
// Reverse args
#define PARENS ()
#define EXPAND(...) EXPAND4(EXPAND4(EXPAND4(EXPAND4(__VA_ARGS__))))
#define EXPAND4(...) EXPAND3(EXPAND3(EXPAND3(EXPAND3(__VA_ARGS__))))
#define EXPAND3(...) EXPAND2(EXPAND2(EXPAND2(EXPAND2(__VA_ARGS__))))
#define EXPAND2(...) EXPAND1(EXPAND1(EXPAND1(EXPAND1(__VA_ARGS__))))
#define EXPAND1(...) __VA_ARGS__
#define REVERSE(...) __VA_OPT__(EXPAND(REVERSE_HELPER(__VA_ARGS__)))
#define REVERSE_HELPER(el, ...) __VA_OPT__(REVERSE_AGAIN PARENS (__VA_ARGS__), ) el
#define REVERSE_AGAIN() REVERSE_HELPER
// Recursive Left Fold
#define FOR_EACH_L(fn, ...) __VA_OPT__(FOR_EACH_APPLY0(FOR_EACH_RESULT, FOR_EACH_L_4(fn,,__VA_ARGS__)))
#define FOR_EACH_L_4(fn, res, ...) FOR_EACH_APPLY4(FOR_EACH_L_3, FOR_EACH_APPLY4(FOR_EACH_L_3, FOR_EACH_APPLY4(FOR_EACH_L_3, fn, res __VA_OPT__(, __VA_ARGS__))))
#define FOR_EACH_L_3(fn, res, ...) FOR_EACH_APPLY3(FOR_EACH_L_2, FOR_EACH_APPLY3(FOR_EACH_L_2, FOR_EACH_APPLY3(FOR_EACH_L_2, fn, res __VA_OPT__(, __VA_ARGS__))))
#define FOR_EACH_L_2(fn, res, ...) FOR_EACH_APPLY2(FOR_EACH_L_1, FOR_EACH_APPLY2(FOR_EACH_L_1, FOR_EACH_APPLY2(FOR_EACH_L_1, fn, res __VA_OPT__(, __VA_ARGS__))))
#define FOR_EACH_L_1(fn, res, ...) FOR_EACH_APPLY1(FOR_EACH_L_0, FOR_EACH_APPLY1(FOR_EACH_L_0, FOR_EACH_APPLY1(FOR_EACH_L_0, fn, res __VA_OPT__(, __VA_ARGS__))))
#define FOR_EACH_L_0(fn, res, ...) fn, FOR_EACH_FIRST(__VA_OPT__(fn(res, FOR_EACH_FIRST(__VA_ARGS__)), ) res) __VA_OPT__(FOR_EACH_TAIL(__VA_ARGS__))
#define FOR_EACH_APPLY4(fn, ...) fn(__VA_ARGS__)
#define FOR_EACH_APPLY3(fn, ...) fn(__VA_ARGS__)
#define FOR_EACH_APPLY2(fn, ...) fn(__VA_ARGS__)
#define FOR_EACH_APPLY1(fn, ...) fn(__VA_ARGS__)
#define FOR_EACH_APPLY0(fn, ...) fn(__VA_ARGS__)
#define FOR_EACH_FIRST(el, ...) el
#define FOR_EACH_TAIL(el, ...) __VA_OPT__(, __VA_ARGS__)
#define FOR_EACH_RESULT(fn, res, ...) res
// Right fold
#define FOR_EACH_R(fn, ...) __VA_OPT__(FOR_EACH_R_APPLY(FOR_EACH_L, fn, REVERSE(__VA_ARGS__)))
#define FOR_EACH_R_APPLY(fn, ...) fn(__VA_ARGS__)
// For testing
#define MY_FUNC(nested, var) (nested | var)
#define NEST_RECURSIVE(...) FOR_EACH_R(MY_FUNC, __VA_ARGS__)
NEST_RECURSIVE(A, B, C, D, E, F, G)