14

Is there a better way to "overload" a macro like this? I need a macro that accepts various numbers of parameters.

#define DEBUG_TRACE_1(p1) std::string p[] = {p1}; log _log(__FUNCTION__, p, 1)
#define DEBUG_TRACE_2(p1, p2) std::string p[] = {p1, p2}; log _log(__FUNCTION__, p, 2)
#define DEBUG_TRACE_3(p1, p2, p3) std::string p[] = {p1, p2, p3}; log _log(__FUNCTION__, p, 3)
#define DEBUG_TRACE_4(p1, p2, p3, p4) std::string p[] = {p1, p2, p3, p4}; log _log(__FUNCTION__, p, 4)
#define DEBUG_TRACE_5(p1, p2, p3, p4, p5) std::string p[] = {p1, p2, p3, p4, p5}; log _log(__FUNCTION__, p, 5)

Called like this

DEBUG_TRACE_2("more", "params");
a3f
  • 8,517
  • 1
  • 41
  • 46
multiholle
  • 3,050
  • 8
  • 41
  • 60
  • 1
    There is some varargs support in the C++ (don't know about ANSI C) macro processor, but every time I try to use it I seem to risk causing an implosion of the known universe. – Hot Licks Jan 16 '12 at 21:58
  • 1
    A little bit here:http://stackoverflow.com/questions/679979/how-to-make-a-variadic-macro-variable-number-of-arguments – Hot Licks Jan 16 '12 at 21:59
  • 1
    `#define DEBUG_TRACE(ar,n) std::string p[] = ar; log _log(__FUNCTION__,p,n)`, call with `DEBUG_TRACE({"more","params"},2);` was too simple? – Daniel Fischer Jan 16 '12 at 23:25

2 Answers2

23

The easiest way to do your specific example would be with a variadic macro:

#define DEBUG_TRACE(...)                                        \
    do {                                                        \
        std::string p[] = { __VA_ARGS__ };                      \
        log _log(__FUNCTION__, p, (sizeof p) / (sizeof p[0]));  \
    } while (0)

A couple notes:

  1. __VA_ARGS__ is the name for the list of comma-separated arguments supplied to the macro
  2. You can find out how many there are in your case using sizeof since p is a static array
  3. Surrounding your macro code in do..while is often considered good practice because it gives variables (p) a block scope so users can still have a variable with the same name outside the macro, and the while (0) portion nicely accepts a semicolon afterwards without breaking one line if statements

If you need more flexibility than this, you can use a very neat trick to allow you to explicitly "overload" the macro to behave completely differently with a different number of parameters. However, this makes the code much more convoluted and should only be used if it is absolutely necessary. Since it seems like variadic arguments will do fine for your use case, I'll just provide a link: http://efesx.com/2010/07/17/variadic-macro-to-count-number-of-arguments/

Shayan Toqraee
  • 735
  • 8
  • 18
Aria Buckles
  • 923
  • 5
  • 10
  • 1
    Obviously only a typo but the macro expands to just `do {`. The rest of the lines except the last need to be slashed too. – ahcox Aug 14 '12 at 23:35
  • +1 for prompting me to double-check a heavily used logging macro, and thereby defusing a ticking time bomb... – John Auld Feb 24 '14 at 23:33
  • 1
    The link seems dead. Here is an archived version: http://web.archive.org/web/20140312145707/http://cplusplus.co.il:80/2010/07/17/variadic-macro-to-count-number-of-arguments/ – Vladimir Reshetnikov Nov 01 '17 at 00:15
14

It is possible to use the standard C /C++ variadic args in macros, at least in gcc (EDIT: apparently they are standardized, and MS c compiler also has them).

See this page for some information on how this works.

There is also another question on this site which may be helpful for you.

Community
  • 1
  • 1
a_m0d
  • 12,034
  • 15
  • 57
  • 79
  • 5
    Variadic macros were standardized in C99 and C++11: http://en.wikipedia.org/wiki/Variadic_macro – Thomas Jan 16 '12 at 21:56
  • 2
    It's also supported in C++11: "If there is a `...` in the identifier-list in the macro definition, then the trailing arguments, including any separating comma preprocessing tokens, are merged to form a single item: the variable arguments. The number of arguments so combined is such that, following merger, the number of arguments is one more than the number of parameters in the macro definition" .. "An identifier `__VA_ARGS__` that occurs in the replacement list shall be treated as if it were a parameter, and the variable arguments shall form the preprocessing tokens used to replace it." – Ben Voigt Jan 16 '12 at 21:58