C - Variadic宏,它扩展为每个参数的宏调用集

时间:2015-07-27 13:49:02

标签: c macros function-pointers variadic-macros

我希望有一个宏调用,它接受多个函数指针,每个函数指针由第二个宏调用,这是一个函数声明。

我希望表单上有两个宏

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”正是我所需要的。

2 个答案:

答案 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在数十亿次迭代中有一个限制,你在实践中不会遇到这种情况。)