MSalters is right; identifiers with single underscores are reserved. If your macros are active when including anything in the implementation, it could clash when you least expect it.
After compiling VS warns about ...
I suspect based on this quote that you're debugging your macros by trying to compile them. A much better approach would be to use only the preprocessor. In Microsoft, you can do this by running cl /EP foo.h
in the command line from a development console (or after running VCVARSALL
for your particular implementation).
Now to the macros:
#define _COUNT_N(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N
#define _COUNT(...) _COUNT_N("ignore", ## __VA_ARGS__, _10, _9, _8, _7, _6, _5, _4, _3, _2, _1, _0)
#define _EXPAND(...) __VA_ARGS__
_COUNT
needs an expansion step, otherwise it's useless. This is better:
#define COUNT_N(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N
#define COUNT(...) EXPAND(COUNT_N( , __VA_ARGS__, _10, _9, _8, _7, _6, _5, _4, _3, _2, _1, _0))
#define EXPAND(...) __VA_ARGS__
Now:
COUNT() COUNT(a) COUNT(a,b)
...expands to:
_1 _1 _2
This is technically correct. COUNT()
has one argument (it's empty). The reason this doesn't return _0
in Microsoft is because of the expansion step... the very thing allowing the COUNT
macro to work in the first place. If you want COUNT()
to return 0
, you'll need to add another level of indirection and use CALL
(since argument list needs to expand once to trigger the comma elision):
#define COUNT_N(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N
#define COUNT_M(...) EXPAND(COUNT_N( __VA_ARGS__, _10, _9, _8, _7, _6, _5, _4, _3, _2, _1, _0))
#define COUNT(...) CALL(COUNT_M,(, __VA_ARGS__))
#define CALL(X,Y) X Y
#define EXPAND(...) __VA_ARGS__
...and now COUNT()
returns _0
; be aware this is Microsoft specific.
Putting it together
#define CONCAT_DETAIL(l, r) l##r
#define CONCAT(l, r) CONCAT_DETAIL(l, r)
#define COUNT_N(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N
#define COUNT_M(...) EXPAND(COUNT_N( __VA_ARGS__, _10, _9, _8, _7, _6, _5, _4, _3, _2, _1, _0))
#define COUNT(...) CALL(COUNT_M,(, __VA_ARGS__))
#define CALL(X,Y) X Y
#define EXPAND(...) __VA_ARGS__
#define CLASS_BODY(...) CONCAT(EXPAND(COUNT(__VA_ARGS__)),_DERIVED)(__VA_ARGS__)
CLASS_BODY()
CLASS_BODY(arg1)
CLASS_BODY(arg1,arg2)
...expands to:
_0_DERIVED()
_1_DERIVED(arg1)
_2_DERIVED(arg1,arg2)
Of course, you're just generating identifiers starting with _
now.