Can MACros Be Overloaded by Number of Arguments

Overloading Macro on Number of Arguments

Simple as:

#define GET_MACRO(_1,_2,_3,NAME,...) NAME
#define FOO(...) GET_MACRO(__VA_ARGS__, FOO3, FOO2)(__VA_ARGS__)

So if you have these macros, they expand as described:

FOO(World, !)         // expands to FOO2(World, !)
FOO(foo,bar,baz) // expands to FOO3(foo,bar,baz)

If you want a fourth one:

#define GET_MACRO(_1,_2,_3,_4,NAME,...) NAME
#define FOO(...) GET_MACRO(__VA_ARGS__, FOO4, FOO3, FOO2)(__VA_ARGS__)

FOO(a,b,c,d) // expands to FOO4(a,b,c,d)

Naturally, if you define FOO2, FOO3 and FOO4, the output will be replaced by those of the defined macros.

Can macros be overloaded by number of arguments?

(Edit: See the end for a ready-made solution.)

To get an overloaded macro, first we need a macro which selects between several implementations. This part doesn't use a variadic macro. Then a variadic macro which generically counts its arguments produces a selector. Plugging the argument count into a dispatcher produces an overloaded macro.

Caveat: This system cannot tell the difference between zero and one arguments because there is no difference between no argument, and a single empty argument. They both look like MACRO().


To select between implementations, use the macro catenation operator with a series of function-like macros.

#define select( selector, ... ) impl ## _ ## selector( __VA_ARGS__ )
#define impl_1() meh
#define impl_2( abc, xyz ) # abc "wizza" xyz()
//etc

// usage: select( 1 ) => impl_1() => meh
// select( 2, huz, bar ) => impl_2( huzza, bar ) => "huz" "wizza" bar()

Because the ## operator suppresses macro expansion of its arguments, it's better to wrap it in another macro.

#define CAT( A, B ) A ## B
#define SELECT( NAME, NUM ) CAT( NAME ## _, NUM )

To count arguments, use __VA_ARGS__ to shift arguments like so (this is the clever part):

#define GET_COUNT( _1, _2, _3, _4, _5, _6 /* ad nauseam */, COUNT, ... ) COUNT
#define VA_SIZE( ... ) GET_COUNT( __VA_ARGS__, 6, 5, 4, 3, 2, 1 )

Library code:

#define CAT( A, B ) A ## B
#define SELECT( NAME, NUM ) CAT( NAME ## _, NUM )

#define GET_COUNT( _1, _2, _3, _4, _5, _6 /* ad nauseam */, COUNT, ... ) COUNT
#define VA_SIZE( ... ) GET_COUNT( __VA_ARGS__, 6, 5, 4, 3, 2, 1 )

#define VA_SELECT( NAME, ... ) SELECT( NAME, VA_SIZE(__VA_ARGS__) )(__VA_ARGS__)

Usage:

#define MY_OVERLOADED( ... ) VA_SELECT( MY_OVERLOADED, __VA_ARGS__ )
#define MY_OVERLOADED_1( X ) foo< X >
#define MY_OVERLOADED_2( X, Y ) bar< X >( Y )
#define MY_OVERLOADED_3( X, Y, Z ) bang_ ## X< Y >.Z()

Overload macro as variable and function

It's not a macro, but looks like it

struct SmartMacro {
constexpr operator int() const noexcept { return 3; }
constexpr int operator()(int a, int b) const noexcept { return a + b; }
};
constexpr SmartMacro FOO;

int main() {
int a = FOO(0,1);
int b = FOO;
std::cout << a + b;
return 0;
}

Macro overloading

Edit ------------------------------------------------look here----------------------------------------------------------------->

(Overloading macro on number of arguments)

// functions, or macros, ....
void bar(){}
void bar(int){}

#define EXPAND(X) X // for MSVC10 compatibility

// compute number of (variadic) macro arguments
// from http://groups.google.com/group/comp.std.c/browse_thread/thread/77ee8c8f92e4a3fb/346fc464319b1ee5?pli=1
#define PP_NARG(...) EXPAND( PP_NARG_(__VA_ARGS__, PP_RSEQ_N()) )
#define PP_NARG_(...) EXPAND( PP_ARG_N(__VA_ARGS__) )
#define PP_ARG_N(_1, _2, _3, N, ...) N
#define PP_RSEQ_N() 3, 2, 1, 0

// macro for exactly 2 arguments
#define FOO_2(_1, _2) bar()
// macro for exactly 3 arguments
#define FOO_3(_1, _2, _3) bar(_2)

// macro selection by number of arguments
#define FOO_(N) FOO_##N
#define FOO_EVAL(N) FOO_(N)
#define FOO(...) EXPAND( FOO_EVAL(EXPAND( PP_NARG(__VA_ARGS__) ))(__VA_ARGS__) )

int main()
{
int something = 42;
FOO("daf", sfdas);
FOO("fdsfs", something, 5);
}

Preprocessor output:

void bar(){}
void bar(int){}

int main()
{
int something = 42;
bar();
bar(something);
}

Edit2: Seems like VS2010 has some issues with __VA_ARGS__ and macro replacement.

UPDATE: It's ... a bug?? (also see this SO question):

#define MACRO2(PARAM0, PARAM1, ...) arg 0: >PARAM0<    arg 1: >PARAM1<    \
additional args: >__VA_ARGS__<
#define MACRO1(...) MACRO2(__VA_ARGS__, OTHERARG_0, OTHERARG_1)

MACRO1(ARG0, ARG1);

Preprocessor output:

arg 0: >ARG0, ARG1<    arg 1: >OTHERARG_0<    additional args: >OTHERARG_1<;

For a workaround, see the linked SO question. I've updated the original answer (code) above and tested it with MSVC10 -> works now.

macros with variable number of arguments

You can use __VA_ARGS__ macro

for example:

WriteToLogParamsFunc(const char *__file, int __line, const char* __func, int nLogLevel, const char *szMessage, ...);

#define WriteToLogParams(nLogLevel, szMessage, ...) WriteToLogParamsFunc(__FILE__, __LINE__, __FUNCTION__, nLogLevel, szMessage, __VA_ARGS__ )

Overload C macros

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/



Related Topics



Leave a reply



Submit