我正在尝试在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__)
答案 0 :(得分:2)
简短的回答,是的,它可以通过便携方式实现。
答案很长:它很复杂,你可能不想自己实现它。有一些方法可以计算宏接收的参数,然后根据该数字采取操作。 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
。
答案 1 :(得分:1)
在this answer中有解释的技术应该允许您计算参数的数量,并使用object
和method
作为前两个参数。