C 预处理器中宏参数的广义迭代
Generalized iteration over arguments of macro in the C preprocessor
这里有几个关于 C 中可变参数宏的问题。这些包括:
- How to make a variadic macro (variable number of arguments) 解释了基础知识,例如,将可变数量的参数传递给
printf
等函数
- Is it possible to iterate over arguments in variadic macros?,它解释了如何将宏迭代地应用于可变参数宏的每个参数。
- https://github.com/swansontec/map-macro 这解释了如何对
我的问题与迭代技术有关。我对具有这种通用语义的宏感兴趣。
ITERATE(Before, Action, Between, After, Empty, ...)
将 Before
放在所有扩展之前,将 Action
应用于每个参数,在每两个连续的应用程序之间放置 Between
,最后将 [=16 的扩展放在=].而且,如果argument的个数有了这样的宏,应该可以写成
// Loop elements
#define A(x) (x)
#define Befor (
#define After )
#define Between ||
#define Empty 1
// Define an OR macro
#define OR(...) ITERATE(Before, A, Between, Empty, __VA_ARGS__)
// Use it
OR() // Expands to 1
OR(a) // Expands to ((a))
OR(a,b) // Expands to ((a)||(b))
OR(a,b,c) // Expands to to ((a)||(b)||(c))
目的当然不是写OR函数。通用功能可能适用于更复杂的应用程序。例如,用于定义 类 和函数的宏、用于打印轨迹的内容等
我从来不喜欢 recursive REPEAT() 宏惯用语 - 它会生成可怕的一小时长的读取错误消息,这些错误消息是..递归的,所以你不知道错误在哪里,也很难理解 OBSTRUCT(REPEAT_INDIRECT) ()
东西有用。总体而言,根据参数数量重载宏并使用外部工具(shell 脚本或 m4 预处理器)生成 C 源代码更容易,更易于阅读、维护和修复,您还可以扩展宏工具端消除了 C 端递归扩展的负担。考虑到这一点,您的 ITERATE
可以使用现有的预处理器库生成,P99_FOR
或 BOOST_FOREACH
浮现在脑海中。
此外,一直输入 shift
很奇怪 - 我更喜欢蛇形。这是一个没有 Before
和 After
宏的简化示例,并且在参数数量上重载了宏:
#define _in_ITERATE_0(f,b,e) e()
#define _in_ITERATE_1(f,b,e,_1) f(_1)
#define _in_ITERATE_2(f,b,e,_1,...) f(_1)b()_in_ITERATE_1(f,b,e,__VA_ARGS__)
#define _in_ITERATE_3(f,b,e,_1,...) f(_1)b()_in_ITERATE_2(f,b,e,__VA_ARGS__)
// or you could expand it instead of reusing previous one with same result:
#define _in_ITERATE_4(f,b,e,_1,_2,_3,_4) f(_1)b()f(_2)b()f(_3)b()f(_4)
// etc.... generate
#define _in_ITERATE_N(_0,_1,_2,_3,_4,_5,_6,_7,_8,_9,N,...) _in_ITERATE_##N
#define ITERATE(func, between, empty, ...) \
_in_ITERATE_N(0,##__VA_ARGS__,9,8,7,6,5,4,3,2,1,0)(func, between, empty, ##__VA_ARGS__)
#define _in_OR_OP(x) (x)
#define _in_OR_EMPTY() 1
#define _in_OR_BETWEEN() ||
#define OR(...) (ITERATE(_in_OR_OP, _in_OR_BETWEEN, _in_OR_EMPTY, ##__VA_ARGS__))
// Use it
OR() // Expands to (1)
OR(a) // Expands to ((a))
OR(a,b) // Expands to ((a)||(b))
OR(a,b,c) // Expands to to ((a)||(b)||(c))
输出:
(1)
((a))
((a)||(b))
((a)||(b)||(c))
有关根据参数数量重载宏的更多示例,请参阅 this thread。我正在使用 ##
GNU 扩展来删除 __VA_ARGS__
之前的逗号,因为我已经习惯了使用它 - 我认为 __VA_OPT__(,)
现在应该是首选,我不确定。
这里有几个关于 C 中可变参数宏的问题。这些包括:
- How to make a variadic macro (variable number of arguments) 解释了基础知识,例如,将可变数量的参数传递给
printf
等函数
- Is it possible to iterate over arguments in variadic macros?,它解释了如何将宏迭代地应用于可变参数宏的每个参数。
- https://github.com/swansontec/map-macro 这解释了如何对
我的问题与迭代技术有关。我对具有这种通用语义的宏感兴趣。
ITERATE(Before, Action, Between, After, Empty, ...)
将 Before
放在所有扩展之前,将 Action
应用于每个参数,在每两个连续的应用程序之间放置 Between
,最后将 [=16 的扩展放在=].而且,如果argument的个数有了这样的宏,应该可以写成
// Loop elements
#define A(x) (x)
#define Befor (
#define After )
#define Between ||
#define Empty 1
// Define an OR macro
#define OR(...) ITERATE(Before, A, Between, Empty, __VA_ARGS__)
// Use it
OR() // Expands to 1
OR(a) // Expands to ((a))
OR(a,b) // Expands to ((a)||(b))
OR(a,b,c) // Expands to to ((a)||(b)||(c))
目的当然不是写OR函数。通用功能可能适用于更复杂的应用程序。例如,用于定义 类 和函数的宏、用于打印轨迹的内容等
我从来不喜欢 recursive REPEAT() 宏惯用语 - 它会生成可怕的一小时长的读取错误消息,这些错误消息是..递归的,所以你不知道错误在哪里,也很难理解 OBSTRUCT(REPEAT_INDIRECT) ()
东西有用。总体而言,根据参数数量重载宏并使用外部工具(shell 脚本或 m4 预处理器)生成 C 源代码更容易,更易于阅读、维护和修复,您还可以扩展宏工具端消除了 C 端递归扩展的负担。考虑到这一点,您的 ITERATE
可以使用现有的预处理器库生成,P99_FOR
或 BOOST_FOREACH
浮现在脑海中。
此外,一直输入 shift
很奇怪 - 我更喜欢蛇形。这是一个没有 Before
和 After
宏的简化示例,并且在参数数量上重载了宏:
#define _in_ITERATE_0(f,b,e) e()
#define _in_ITERATE_1(f,b,e,_1) f(_1)
#define _in_ITERATE_2(f,b,e,_1,...) f(_1)b()_in_ITERATE_1(f,b,e,__VA_ARGS__)
#define _in_ITERATE_3(f,b,e,_1,...) f(_1)b()_in_ITERATE_2(f,b,e,__VA_ARGS__)
// or you could expand it instead of reusing previous one with same result:
#define _in_ITERATE_4(f,b,e,_1,_2,_3,_4) f(_1)b()f(_2)b()f(_3)b()f(_4)
// etc.... generate
#define _in_ITERATE_N(_0,_1,_2,_3,_4,_5,_6,_7,_8,_9,N,...) _in_ITERATE_##N
#define ITERATE(func, between, empty, ...) \
_in_ITERATE_N(0,##__VA_ARGS__,9,8,7,6,5,4,3,2,1,0)(func, between, empty, ##__VA_ARGS__)
#define _in_OR_OP(x) (x)
#define _in_OR_EMPTY() 1
#define _in_OR_BETWEEN() ||
#define OR(...) (ITERATE(_in_OR_OP, _in_OR_BETWEEN, _in_OR_EMPTY, ##__VA_ARGS__))
// Use it
OR() // Expands to (1)
OR(a) // Expands to ((a))
OR(a,b) // Expands to ((a)||(b))
OR(a,b,c) // Expands to to ((a)||(b)||(c))
输出:
(1)
((a))
((a)||(b))
((a)||(b)||(c))
有关根据参数数量重载宏的更多示例,请参阅 this thread。我正在使用 ##
GNU 扩展来删除 __VA_ARGS__
之前的逗号,因为我已经习惯了使用它 - 我认为 __VA_OPT__(,)
现在应该是首选,我不确定。