C Preprocessor, Macro “Overloading”

2019-01-12 01:46发布

问题:

I'm trying to do some kind of Macro "Overloading", so that MACRO(something), gets expanded differently than MACRO(something, else).

Using a snippet I got from here (I'm not sure if it's 100% portable) and some functions from the Boost PP Library, I was able to make it work :D

//THESE TWO COUNT THE NUMBER OF ARGUMENTS
#define VA_NARGS_IMPL(_1, _2, _3, _4, _5, N, ...) N
#define VA_NARGS(...) VA_NARGS_IMPL(__VA_ARGS__, 5, 4, 3, 2, 1)

//THIS ONE RETURNS THE PARAMETER AT POSITION _i FROM A LIST OF __VA_ARGS__
#define VA_ARG(_i, ...) BOOST_PP_ARRAY_ELEM(_i, (VA_NARGS(__VA_ARGS__), (__VA_ARGS__)))

//AND THIS ONE IS THE 'OVERLOADED' MACRO ;)
#define TEST(...) BOOST_PP_IF(BOOST_PP_EQUAL(1, VA_NARGS(__VA_ARGS__)), function_A(VA_ARG(0, __VA_ARGS__)), \ //1 parameter
                  BOOST_PP_IF(BOOST_PP_EQUAL(2, VA_NARGS(__VA_ARGS__)), function_B(VA_ARG(0, __VA_ARGS__) + VA_ARG(1, __VA_ARGS__)), \ //2 parameters
                  BOOST_PP_IF(BOOST_PP_EQUAL(3, VA_NARGS(__VA_ARGS__)), function_C(VA_ARG(1, __VA_ARGS__) + VA_ARG(2, __VA_ARGS__)), BOOST_PP_EMPTY())) // 3 parameters and so on ...

So       TEST(a) = function_A(a)
      TEST(a, b) = function_B(a + b)
   TEST(a, b, c) = function_C(b + c)

Now I'm still missing two other things that I want to do:

  1. (This one I don't really care if I never solve it) I believe that a MACRO can be written that when taking up the number of 'variants' and its correspondent 'output' generates a code similar like the one above. Something like TEMPLATE(3, function_A(...), function_B(...), function_C(...)) to generate the example above.

  2. What happens when TEST() is called without arguments? Well, VA_NARGS expands to 1. But the first argument is ""(nothing). I'm trying to find a way to either detect 'zero' arguments in __VA_ARGS__ or to differentiate between a 'null' argument and a real one, in order to extend the 'overloading' function to react to this situation. Any ideas?

回答1:

To answer your question 2 first. Yes, with variadic macros it is also possible to detect an empty argument list. The explanation is a bit lengthy, I have written it up here. It should be relatively easy to combine this approach with the boost macros that you are using.

For your question 1, yes this is also possible. Boost has some iterator macros that come close to this, I think, but they look a bit scary to use. If I understand correctly you have to use something like nested lists (a, (b, (c,d))), not too convenient.

(I wrote a set of macros that can achieve this more directly, but unfortunately the package is not yet ready for release. Contact me in private if you are really interested in it.)

Edit: The P99 package is published in the mean time and contains a lot of stuff over macro "overloading" and type generic macros.