C Preprocessor, Macro "Overloading"
Asked Answered
H

1

4

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?

Holeandcorner answered 6/8, 2010 at 1:40 Comment(6)
Boost -> C++ -> if you are already using C++, do not mess with pre-processor, use plain functions (inlined if you wish). C preprocessor is intentionally dumb so that people wouldn't abuse it.Puente
Is this for C or C++ ? Also note that using varargs with macros is not portable.Furthermost
@Paul R: variadic macros are part of C99.Pogey
@Jens: thanks for pointing that out - they are still not portable though if you want to target e.g. MSVC, since Microsoft still does not support C99.Furthermost
@Paul. MSVC doesn't support C99, but they do support __VA_ARG__ and __VA_ARG__, (2008 express)Avelinaaveline
I'm not using C++, I'm just using Boost PP Libraries for CHoleandcorner
P
5

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.

Pogey answered 6/8, 2010 at 6:31 Comment(1)
Boost iterator macros have several different types of sequences: List (a (b (c,d) ) ), tuples (a,b,c) (length must be known) and lists (a)(b)(c). The latter is the easiest for me to deal with.Avelinaaveline

© 2022 - 2024 — McMap. All rights reserved.