I want a macro to detect whether the passed arg is surrounded by parentheses or not, and call a different macro if so.
e.g.
#define FOO(obj) BAR obj
#define BAR(...) func(__VA_ARGS__)
#define BAR
If I call this with FOO((1, 2, 3))
it'd expand to func(1, 2, 3)
. But if I call it with FOO(1)
it should expand to 1
I know that macro overloading isn't a thing in C, but I'm wondering if there's another way to achieve this behavior from FOO
. I looked into several macro tricks but couldn't figure out a way to do this.
I'm working on a macro library and need this exact behavior.
I have just written this. This can be simplified, it's just the first version that I got on godbolt that worked. Should be enough to get you started.
// if I call this with FOO((1, 2, 3)) it'd expand to func(1, 2, 3).
// But if I call it with FOO(1) it should expand to 1
#define ESCAPE2(...) __VA_ARGS__
#define ESCAPE(...) ESCAPE2 __VA_ARGS__
#define COMMA(...) ,
#define FIRST(T, ...) T
// from https://gustedt.wordpress.com/2010/06/08/detect-empty-macro-arguments/
#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 CONCAT(a, b) a##b
#define XCONCAT(a, b) CONCAT(a, b)
#define IF_1(a, b) a
#define IF_0(a, b) b
#define FOO(...) \
ESCAPE( \
XCONCAT(IF_, HAS_COMMA(FIRST( COMMA __VA_ARGS__ () ))) \
((func __VA_ARGS__), (__VA_ARGS__)) \
)
FOO((1,2,3)) // func (1,2,3)
FOO((1)) // func (1)
FOO(1) // 1
FOO(1,2) // 1,2
This looks nicer. After converting __VA_ARGS__
to a comma, it's just a matter of getting a proper arg position.
#define FOO_ESCAPE(...) __VA_ARGS__
#define FOO_COMMA(...) ,
#define FOO_FIRST(T, ...) T
#define FOO_THIRD(_1,_2,_3,...) \
FOO_ESCAPE _3
#define FOO_XTHIRD(...) \
FOO_THIRD(__VA_ARGS__)
#define FOO(...) \
FOO_XTHIRD(__VA_OPT__(FOO_FIRST(FOO_COMMA __VA_ARGS__)), \
(func __VA_ARGS__), (__VA_ARGS__) )
FOO((1,2,3))
FOO((1))
FOO()
FOO(1)
FOO(1,2)