Need a way to support nested calls in variadic macros with optional argument. same as this but C99 compatible
GNU gcc extension for ##
operator prevents nested calls from being expanded, see code below.
#define send(obj, msg, ...) find_method(obj, msg)(obj, ##__VA_ARGS__)
/* Ok */
send(0, "+", 1);
find_method(0, "+")(0, 1);
/* Ok. nested call as macros named argument */
send(send(5, "increment"), "+", 1);
find_method(find_method(5, "increment")(5), "+")(find_method(5, "increment")(5), 1);
/* Fail. nested call as macros variable argument i.e. `send` macro is not expanded */
send(0, "+", send(5, "increment"));
find_method(0, "+")(0, send(5, "increment"));
/*
* preprocess with next commands
*
* gcc-4.9 -Wall -std=c99 -E -c file.c | less
* clang-3.8 -Wall -std=c99 -E -c file.c | less
*/
I've modified Jens Gustedt solution to place optional comma, see code below.
Are there more concise alternatives ?
#define _ARG16( \
_0, _1, _2, _3, _4, \
_5, _6, _7, _8, _9, \
_10, _11, _12, _13, _14, \
_15, ...) _15
#define HAS_COMMA(...) \
_ARG16(__VA_ARGS__, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0)
#define _TRIGGER_PARENTHESIS_(...) ,
#define OPTIONAL_COMMA(...) \
_ISEMPTY( \
/* test if there is just one argument, eventually an empty \
one */ \
HAS_COMMA(__VA_ARGS__), \
/* test if _TRIGGER_PARENTHESIS_ together with the argument \
adds a comma */ \
HAS_COMMA(_TRIGGER_PARENTHESIS_ __VA_ARGS__), \
/* test if the argument together with a parenthesis \
adds a comma */ \
HAS_COMMA(__VA_ARGS__ (/*empty*/)), \
/* test if placing it between _TRIGGER_PARENTHESIS_ and the \
parenthesis adds a comma */ \
HAS_COMMA(_TRIGGER_PARENTHESIS_ __VA_ARGS__ (/*empty*/)) \
)
#define SPACE_SYMBOL
#define COMMA_SYMBOL ,
#define ARG3(_0, _1, _2, ...) _2
#define OPTIONAL_COMMA_FROM(...) ARG3(__VA_ARGS__, SPACE_SYMBOL, COMMA_SYMBOL)
#define PASTE5(_0, _1, _2, _3, _4) _0 ## _1 ## _2 ## _3 ## _4
#define _ISEMPTY(_0, _1, _2, _3) \
OPTIONAL_COMMA_FROM(PASTE5(_IS_EMPTY_CASE_, _0, _1, _2, _3))
#define _IS_EMPTY_CASE_0001 ,
#define send(obj, msg, ...) \
find_method(obj, msg)(obj OPTIONAL_COMMA(__VA_ARGS__) __VA_ARGS__)
/* Ok */
send(0, "+", 1);
/* Ok */
send(send(5, "increment"), "+", 1);
/* Ok */
send(0, "+", send(5, "increment"));
Update:
H Walters thanks for idea.
Didn't noticed approach with macros overloading in first place
#define SEND_NO_ARG(obj, msg) find_method(obj, msg)(obj)
#define SEND_ARG(obj, msg, ...) find_method(obj, 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_SELECTOR(...) \
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_SELECTOR(__VA_ARGS__)(__VA_ARGS__)