I want to create a C++ macro that can either take in no parameters, or a single parameter.
FUNC() or FUNC(1) should both work.
I was wondering how to use variadic macros in order to achieve this.
Func() should map to do_something_different.
Func(1) should map to do_something(1).
Note that they are different statements
Variadic macros can be helpful in similar cases, but you don't need them (and in fact can't use them) for this specific example, because it doesn't involve a variable number of arguments but only the changing nature of one argument (note that a nonexistent token can be a valid macro argument for many purposes, including this one).
You can dispatch on an argument if you know all of its forms in advance (or if you don't care about some not resulting in further expansions), using the ##
operator:
#define FUNC(X) FUNC_IMPL_ ## X
#define FUNC_IMPL_ do_something_different
#define FUNC_IMPL_1 do_something(1)
FUNC() // -> do_something_different
FUNC(1) // -> do_something(1)
##
concatenates two tokens to form one, which is then subject to re-expansion, so you can use it to modify macro names based on arguments and thus expand to different outputs. An empty argument is allowed to be used in this way too, handily.
There are many ways to make this much more complicated, with varying argument numbers and stages of expansion and so on, depending on what else you want to achieve.
e.g. detecting any argument to FUNC
and passing it through to do_something
requires quite a bit of expansion trickery:
#define ONE_OR_TWO(...) ONE_OR_TWO_(__VA_ARGS__, 2, 1,)
#define ONE_OR_TWO_(_1, _2, X, ...) X
#define CAT(A, B) CAT_(A, B)
#define CAT_(A, B) A ## B
#define FUNC(X) CAT(DO_SOMETHING_, ONE_OR_TWO(FUNC_IMPL_ ## X))(X)
#define FUNC_IMPL_ ,
#define DO_SOMETHING_2(_) do_something_different
#define DO_SOMETHING_1(X) do_something(X)
FUNC() // -> do_something_different
FUNC(1) // -> do_something(1)
FUNC(2) // -> do_something(2)
This also demonstrates a quirk of ##
, which is that it pastes before expanding its operands, so it needs a helper macro if you want to expand-and-paste. On the other hand, the fact that empty parentheses are detected as containing an invisible argument means we have to rely on ##
to detect them.
Using macros for anything nontrivial can be quite complicated. (I'm not condoning the use of this style.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With