我希望有一个宏调用,它接受多个函数指针,每个函数指针由第二个宏调用,这是一个函数声明。
我希望表单上有两个宏
SELECT p.name
FROM Persons p
LEFT JOIN Logs l ON p.id = l.person_id
WHERE l.id IS NULL
这样称为
#define FUNCTION_DEF(func) extern int func(void);
#define FUNCTION_DEFS(...) (???)
扩展为
FUNCTION_DEFS(
myFunc1,
myFunc2,
otherFunc1,
otherFunc2,
defaultFunc
)
换句话说,对FUNCTION_DEF(myFunc1)
FUNCTION_DEF(myFunc2)
FUNCTION_DEF(otherFunc1)
FUNCTION_DEF(otherFunc2)
FUNCTION_DEF(defaultFunc)
的这一单个调用扩展为所有可变参数的函数声明。
目前我只是跳过第一步并在每个函数指针上调用FUNCTION_DEFS
,但是解决这个问题会很好。
这可能吗?
感谢@Vality将我介绍给X-Macro。我发现这篇文章“Real-world use of X-Macros”正是我所需要的。
答案 0 :(得分:2)
我不相信你想要的是使用标准的C预处理器。但是,使用X宏可以实现类似的解决方案。
要使用它们执行等效的代码,首先要将函数列表定义为X宏:
#define FUNCTION_LIST_A \
X(myFunc1) \
X(myFunc2) \
X(otherFunc1) \
X(otherFunc2) \
X(defaultFunc)
然后使用特定的宏实例化这些函数,然后定义要对每个函数执行的宏:
#define X(name) FUNCTION_DEF(name)
FUNCTION_LIST_A
#undef X
然后将扩展为:
FUNCTION_DEF(myFunc1)
FUNCTION_DEF(myFunc2)
FUNCTION_DEF(otherFunc1)
FUNCTION_DEF(otherFunc2)
FUNCTION_DEF(defaultFunc)
希望这很有用,并且接近你想要的。不可否认,语法明显不同,但如果你想要完成的是将一个选定的函数或宏应用于整个数据列表(在这种情况下是函数指针),这是我所知道的最常用的方法,使用c预处理器
答案 1 :(得分:1)
有很多方法可以做到这一点。最简单的是为每个可能的长度预定义循环的版本(在较小的版本上构建),并根据要迭代的参数的数量选择正确的循环:
#define M_NARGS(...) M_NARGS_(__VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
#define M_NARGS_(_10, _9, _8, _7, _6, _5, _4, _3, _2, _1, N, ...) N
#define M_CONC(A, B) M_CONC_(A, B)
#define M_CONC_(A, B) A##B
#define M_ID(...) __VA_ARGS__
#define M_FOR_EACH(ACTN, ...) M_CONC(M_FOR_EACH_, M_NARGS(__VA_ARGS__)) (ACTN, __VA_ARGS__)
#define M_FOR_EACH_0(ACTN, E) E
#define M_FOR_EACH_1(ACTN, E) ACTN(E)
#define M_FOR_EACH_2(ACTN, E, ...) ACTN(E) M_FOR_EACH_1(ACTN, __VA_ARGS__)
#define M_FOR_EACH_3(ACTN, E, ...) ACTN(E) M_FOR_EACH_2(ACTN, __VA_ARGS__)
#define M_FOR_EACH_4(ACTN, E, ...) ACTN(E) M_FOR_EACH_3(ACTN, __VA_ARGS__)
#define M_FOR_EACH_5(ACTN, E, ...) ACTN(E) M_FOR_EACH_4(ACTN, __VA_ARGS__)
//...etc
#define FUNCTION_DEF(func) extern int func(void);
#define FUNCTION_DEFS(...) M_FOR_EACH(FUNCTION_DEF, __VA_ARGS__)
您还可以使用传统的递归技术制作更通用的解决方案,但这通常需要支持库(例如[1],[2])来提供机制,因为直接定义的宏不是支持递归。
这是因为预处理器中的所有循环都必须具有预定的上限,这是没有直接宏递归的结果:您可以在上述代码等简单情况下将该限制硬编码到循环实现中,或者您可以让你的循环构造运算符的递归驱动程序包含限制,并为请求它们的构造提供 N 迭代(后者的优点是它可以让你集中,然后忘记,限制,只要它足够高,例如Order-PP在数十亿次迭代中有一个限制,你在实践中不会遇到这种情况。)