9

我正在尝试在 C 中进行面向对象,并希望有一个用于表示法的语法糖宏

object->vtable->method(object, arg1, arg2)

进入

send(object, method, arg1, arg2)

不幸的是,当一个方法不带参数时,就会出现尾随逗号问题

send(object, method)

object->vtable->method(object, )

是否有任何可移植(无##__VA_ARGS__或 Visual Studio)的方式来执行此操作?

我想出了一个,但我需要交换对象和方法

#define FIRST_ARG_(N, ...) N
#define FIRST_ARG(args) FIRST_ARG_(args)
#define send(msg, ...) \
 FIRST_ARG(__VA_ARGS__)->vtable->msg(__VA_ARGS__)

许可证

send(method, object)
send(method, object, arg1, arg2)

编辑

在下面两个好的答案的帮助下,我将使用这些宏来完成。它最多可以使用 16 个参数,但可以轻松扩展

#define SEND_NO_ARG(obj, msg) obj->vtable->msg(obj)
#define SEND_ARG(obj, msg, ...) obj->vtable->msg(obj, __VA_ARGS__)

#define GET_18TH_ARG(arg1, arg2, arg3, arg4, arg5, \
    arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, \
    arg16, arg17, arg18, ...) arg18
#define SEND_MACRO_CHOOSER(...) \
    GET_18TH_ARG(__VA_ARGS__, \
            SEND_ARG, SEND_ARG, SEND_ARG, SEND_ARG, SEND_ARG, \
            SEND_ARG, SEND_ARG, SEND_ARG, SEND_ARG, SEND_ARG, \
            SEND_ARG, SEND_ARG, SEND_ARG, SEND_ARG, SEND_ARG, \
            SEND_NO_ARG, )

#define SEND(...) SEND_MACRO_CHOOSER(__VA_ARGS__)(__VA_ARGS__)
4

2 回答 2

4

简短的回答,是的,可以通过便携式方式进行。

长答案:这很复杂,您可能不想自己实现。有一些方法可以计算宏接收到的参数,然后根据该数字采取行动。P99实现了一系列可以帮助您实现这一目标的宏。如果您要实现两个基本宏send_2,并且send_more对于这两种情况,您可以实现send

#define send(...)                     \
 P99_IF_LT(P99_NARG(__VA_ARGS__), 3)  \
 (send_2(__VA_ARGS__))                \
 (send_more(__VA_ARGS__))

从技术上讲,P99 中的这些构造有一个限制,即它们不能处理超过 150 个(左右)的send.

顺便说一句,您可能知道,调用宏send并不是一个好主意。通常人们更喜欢宏是全大写的。此外,在大多数情况下,最好使用一个对您的库/包唯一的名称前缀,例如AC245_SEND.

于 2013-12-28T20:53:58.923 回答
1

这个答案中,解释了一种技术,它应该允许您计算参数的数量并使用objectmethod作为前两个参数。

于 2013-12-28T20:16:00.763 回答