I work on a project, and I need to simulate a recursive macro (here TEST_COLUMN). But it fail on visual 2013.
On gcc, it work correctly, but with visual, I have an error.
So, to debug this macro, I use static_assert (maybe there is a better way).
Each time, in the macros TEST_COLUMN_X(name, ...) the value of name contain ALL the parameters, and not only the first one.
If anyone have an idea to fix this.
Here is the minimal code needed to reproduce it:
#define STR_HELPER(x) #x
#define STR(x) STR_HELPER(x) //transform x to char
#define EXPAND(x) x
#define NUM_ARGS_HELPER(X,X64,X63,X62,X61,X60,X59,X58,X57,X56,X55,X54,X53,X52,X51,X50,X49,X48,X47,X46,X45,X44,X43,X42,X41,X40,X39,X38,X37,X36,X35,X34,X33,X32,X31,X30,X29,X28,X27,X26,X25,X24,X23,X22,X21,X20,X19,X18,X17,X16,X15,X14,X13,X12,X11,X10,X9,X8,X7,X6,X5,X4,X3,X2,X1,N,...) N
//count to number of argument containing
#define NUM_ARGS(...) EXPAND(NUM_ARGS_HELPER(0, __VA_ARGS__ ,64,63,62,61,60,59,58,57,56,55,54,53,52,51,50,49,48,47,46,45,44,43,42,41,40,39,38,37,36,35,34,33,32,31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0)) in __VA_ARGS__
//define each level of the macro
#define TEST_COLUMN_0 ;
#define TEST_COLUMN_1(name) static_assert(false,"TEST_COLUMN_1 " STR(name));
#define TEST_COLUMN_2(name,...) static_assert(false,"TEST_COLUMN_2 " STR(name)); //TEST_COLUMN_1(__VA_ARGS__)
#define TEST_COLUMN_3(name,...) static_assert(false,"TEST_COLUMN_3 " STR(name)); //TEST_COLUMN_2(__VA_ARGS__)
#define TEST_COLUMN_4(name,...) static_assert(false,"TEST_COLUMN_4 " STR(name)); TEST_COLUMN_3(__VA_ARGS__)
//tricks to call the correct macro (TEST_COLUMN_X)
#define TEST_COLUMN_N1(N,...) TEST_COLUMN_##N(__VA_ARGS__)
#define TEST_COLUMN(N,...) TEST_COLUMN_N1(N,__VA_ARGS__)
//recursive macro
#define TEST_STATIC_COLUMN(...) TEST_COLUMN(NUM_ARGS(__VA_ARGS__), __VA_ARGS__)
int main(int argc, char* argv[])
{
TEST_STATIC_COLUMN(a, b, c);
return 0;
}
Output :
main.cpp(21): error C2338: TEST_COLUMN_3 a, b, c
but it should be
main.cpp(21): error C2338: TEST_COLUMN_3 a
You can test this using the online compiler http://webcompiler.cloudapp.net/
I don't know why, but adding some call to EXPAND solve this issue:
#define TEST_COLUMN_2(name,...) static_assert(false,"TEST_COLUMN_2 " STR(name)); EXPAND(TEST_COLUMN_1(__VA_ARGS__))
#define TEST_COLUMN_3(name,...) static_assert(false,"TEST_COLUMN_3 " STR(name)); EXPAND(TEST_COLUMN_2(__VA_ARGS__))
#define TEST_COLUMN_4(name,...) static_assert(false,"TEST_COLUMN_4 " STR(name)); EXPAND(TEST_COLUMN_3(__VA_ARGS__))
#define TEST_COLUMN_N1(N,...) EXPAND(TEST_COLUMN_##N(__VA_ARGS__))
Related
So I've got a macro that works nicely in GCC, but not in Microsoft's C++ Compiler. I'm hoping somebody might know of a workaround, or perhaps can explain to me why it behaves this way.
I'm sure this macro isn't exactly "standard", but it would really help me out.
Here is a functional example of the macro:
#define VA_NARGS_IMPL(_1, _2, _3, _4, _5, N, ...) N
#define VA_NARGS(...) VA_NARGS_IMPL(__VA_ARGS__, 5, 4, 3, 2, 1)
#define FULLY_EXPANDED(count, ...) \
MAC ## count (__VA_ARGS__)
#define SEMI_EXPANDED(count, ...) FULLY_EXPANDED(count, __VA_ARGS__)
#define EXPAND_THESE(...) SEMI_EXPANDED(VA_NARGS(__VA_ARGS__), __VA_ARGS__)
#define ACTUAL_MACRO(x) parent->GetProperty<x>();
#define MAC1(a) ACTUAL_MACRO(a)
#define MAC2(a,b) MAC1(a) ACTUAL_MACRO(b)
#define MAC3(a,b,c) MAC2(a,b) ACTUAL_MACRO(c)
#define MAC4(a,b,c,d) MAC3(a,b,c) ACTUAL_MACRO(d)
#define MAC5(a,b,c,d,e) MAC4(a,b,c,d) ACTUAL_MACRO(e)
Here is how I might use this macro:
struct MyStructure
{
void Foo()
{
EXPAND_THESE(Property1, Property2, Property3, Property4)
}
Base * parent;
}
Here's how GCC expands the above:
struct MyStructure
{
void Foo()
{
parent->GetProperty<Property1>();
parent->GetProperty<Property2>();
parent->GetProperty<Property3>();
parent->GetProperty<Property4>();
}
Base * parent;
}
But Microsoft for some reason expands all my __VA_ARGS__ as one argument:
struct MyStructure
{
void Foo()
{
parent->GetProperty<Property1, Property2, Property3, Property4>();
}
Base * parent;
}
Does anybody know why this is? Is there some trick I can pull to get Microsoft to expand this like GCC? Maybe toss in a couple extra pairs of parentheses?
Macros like this could really help me out in replacing a bunch of "glue" code, but because of this problem, I can't move it into my VS project. Any help would be greatly appreciated!
Thanks.
I know this question is over two years old, but I thought I would try to give a more polished answer to those who still stumble upon this, like I did.
Jeff Walden's answer works and all, but you have to declare FOO_CHOOSE_HELPER/1/2 for each FOO macro you want to have variadic arguments. I have developed a layer of abstraction to solve this issue. Consider the following:
#define GLUE(x, y) x y
#define RETURN_ARG_COUNT(_1_, _2_, _3_, _4_, _5_, count, ...) count
#define EXPAND_ARGS(args) RETURN_ARG_COUNT args
#define COUNT_ARGS_MAX5(...) EXPAND_ARGS((__VA_ARGS__, 5, 4, 3, 2, 1, 0))
#define OVERLOAD_MACRO2(name, count) name##count
#define OVERLOAD_MACRO1(name, count) OVERLOAD_MACRO2(name, count)
#define OVERLOAD_MACRO(name, count) OVERLOAD_MACRO1(name, count)
#define CALL_OVERLOAD(name, ...) GLUE(OVERLOAD_MACRO(name, COUNT_ARGS_MAX5(__VA_ARGS__)), (__VA_ARGS__))
With this architecture you can define variadic macros as such:
#define ERROR1(title) printf("Error: %s\n", title)
#define ERROR2(title, message)\
ERROR1(title);\
printf("Message: %s\n", message)
#define ERROR(...) CALL_OVERLOAD(ERROR, __VA_ARGS__)
#define ASSERT1(expr) singleArgumentExpansion(expr)
#define ASSERT2(expr, explain) twoArgumentExpansion(expr, explain)
#define ASSERT(...) CALL_OVERLOAD(ASSERT, __VA_ARGS__)
With Jeff's answer you would have to define the macros as follows:
#define ERROR1(title) printf("Error: %s\n", title)
#define ERROR2(title, message)\
ERROR1(title);\
printf("Message: %s\n", message)
#define ERROR_CHOOSE_HELPER2(count) ERROR##count
#define ERROR_CHOOSE_HELPER1(count) ERROR_CHOOSE_HELPER2(count)
#define ERROR_CHOOSE_HELPER(count) ERROR_CHOOSE_HELPER1(count)
#define ERROR(...) GLUE(ERROR_CHOOSE_HELPER(COUNT_ARGS_MAX5(__VA_ARGS__)),\
(__VA_ARGS__))
#define ASSERT1(expr) singleArgumentExpansion(expr)
#define ASSERT2(expr, explain) twoArgumentExpansion(expr, explain)
#define ASSERT_CHOOSE_HELPER2(count) ASSERT##count
#define ASSERT_CHOOSE_HELPER1(count) ASSERT_CHOOSE_HELPER2(count)
#define ASSERT_CHOOSE_HELPER(count) ASSERT_CHOOSE_HELPER1(count)
#define ASSERT(...) GLUE(ASSERT_CHOOSE_HELPER(COUNT_ARGS_MAX5(__VA_ARGS__)),\
(__VA_ARGS__))
It's not a big deal, however I like my code to be as concise as possible. It also helps exponentially, if you are using several variadic macros, to reduce code duplication and the complications that can cause. As far as I know, this method is also portable. I have tested it on many of the most common compilers and they produced the same results.
Example use:
int foo()
{
ASSERT(one); // singleArgumentExpansion(one)
ASSERT(two, "foopy"); // twoArgumentExpansion(two, "foopy")
ERROR("Only print a title");
ERROR("Error title", "Extended error description");
}
Coincidentally, I happened to run into this problem just today, and after enough effort I think I've found a solution for my own purposes. The bug is MSVC treats __VA_ARGS__ as a single token in argument lists. But you can work around this by not using it directly within a macro call argument list. This comment suggests the start of an answer to your problems:
#define VA_NARGS(...) VA_NUM_ARGS_IMPL_((__VA_ARGS__, 5,4,3,2,1))
#define VA_NARGS_IMPL_(tuple) VA_NUM_ARGS_IMPL tuple
#define VA_NARGS_IMPL(_1,_2,_3,_4,_5,N,...) N
But then I suspect you'll likely run into the issue of making sure that gets fully expanded to the actual "N" you want, and not to VA_NARGS_IMPL (arg1, arg2, 5, 4, 3, 2, 1), say. I found that my code (which looked like yours) had to change to expand MAC##code all as one unit, and then that had to be separately combined with the argument list. Here's the code that I found worked for me:
#define ASSERT_HELPER1(expr) singleArgumentExpansion(expr)
#define ASSERT_HELPER2(expr, explain) \
twoArgumentExpansion(expr, explain)
/*
* Count the number of arguments passed to ASSERT, very carefully
* tiptoeing around an MSVC bug where it improperly expands __VA_ARGS__ as a
* single token in argument lists. See these URLs for details:
*
* http://connect.microsoft.com/VisualStudio/feedback/details/380090/variadic-macro-replacement
* http://cplusplus.co.il/2010/07/17/variadic-macro-to-count-number-of-arguments/#comment-644
*/
#define COUNT_ASSERT_ARGS_IMPL2(_1, _2, count, ...) \
count
#define COUNT_ASSERT_ARGS_IMPL(args) \
COUNT_ASSERT_ARGS_IMPL2 args
#define COUNT_ASSERT_ARGS(...) \
COUNT_ASSERT_ARGS_IMPL((__VA_ARGS__, 2, 1, 0))
/* Pick the right helper macro to invoke. */
#define ASSERT_CHOOSE_HELPER2(count) ASSERT_HELPER##count
#define ASSERT_CHOOSE_HELPER1(count) ASSERT_CHOOSE_HELPER2(count)
#define ASSERT_CHOOSE_HELPER(count) ASSERT_CHOOSE_HELPER1(count)
/* The actual macro. */
#define ASSERT_GLUE(x, y) x y
#define ASSERT(...) \
ASSERT_GLUE(ASSERT_CHOOSE_HELPER(COUNT_ASSERT_ARGS(__VA_ARGS__)), \
(__VA_ARGS__))
int foo()
{
ASSERT(one); // singleArgumentExpansion(one)
ASSERT(two, "foopy"); // twoArgumentExpansion(two, "foopy")
}
My mind is too much mush after a few hours solving my own issues to then go and completely solve yours, I'm sorry to say. :-) But I think this is enough to get you to something that works, with a little work.
Microsoft has rewritten the C/C++ preprocessor, but it is not enabled by default for "backwards-compatibility", i.e. they prefer bug-compatibility with their own products instead of portability or standard compliance.
It seems that you can fix the __VA_ARGS__ handling by adding a /experimental:preprocessor flag to the command line.
I am trying to create a macro that would iterate over a defined list of terms, and for each invoke another macro, possibly with additional argument list. Here is what I have got:
#define ITERATE_OVER_TERMS(MACRO, ...) \
MACRO(Term1, __VA_ARGS__) \
MACRO(Term2, __VA_ARGS__) \
MACRO(Term3, __VA_ARGS__) \
... and so on
However, when I was trying to use it with Visual Studio 2015, i get an error
warning C4003: not enough actual parameters for macro 'BODY'
where BODY is the name of the macro passed as the MACRO argument. While technically a warning, it shows that something has gone wrong with the expansion.
In an attempt to narrow down the error, I reduced my example to the following:
#include <iostream>
#define ITERATE(MACRO, ...) \
MACRO(1, __VA_ARGS__) MACRO(2, __VA_ARGS__)
#define BODY(IterationArg, Arg1, Arg2) \
std::cout << IterationArg << Arg1 << Arg2 << std::endl;
int main() {
ITERATE(BODY, 8, 9)
return 0;
}
It gives me the error as shown above, while I expected it to compile succesfully and produce the output
189
289
It does seem to compile with g++, but not Visual Studio.
What am I missing? Is there some walkaround for this to work?
The problem is that Visual Studio expands __VA_ARGS__ after they are being passed into a subsequent macro, and not before. This has caused problems in the past as well, for example here --
Why does this variadic argument count macro fail with VC++?
In your case, consider a simple change in the code:
#include <iostream>
#define ITERATE(MACRO, ...) \
MACRO(1, __VA_ARGS__) MACRO(2, __VA_ARGS__)
#define BODY(IterationArg, Arg1, Arg2) \
std::cout << #Arg1 << std::endl;
int main() {
ITERATE(BODY, 8, 9)
return 0;
}
The argument #Arg1 is stringified, showing us its contents in the output:
8, 9
8, 9
Not what we expected, huh?
A solution is the same as in the linked question: force an expansion through a dummy EXPAND macro:
#define EXPAND(x) x
#define ITERATE(MACRO, ...) \
EXPAND(MACRO(1, __VA_ARGS__)) EXPAND(MACRO(2, __VA_ARGS__))
This gives you the desired result both in VS and gcc.
Trying to get this working in VS2013 (see Variadic macro trick and C++ preprocessor __VA_ARGS__ number of arguments).
It's not a duplicate afaik (versions posted elsewhere only work with GCC).
Any ideas what's wrong with this? I'm almost there...
#define _EXPAND(x) x
#define _VA_NARGS_IMPL(_1_, _2_, _3_, _4_, _5_, N, ...) N
#define _VA_NARGS_IMPL2(...) _EXPAND(_VA_NARGS_IMPL(__VA_ARGS__, 4, 3, 2, 1, 0))
#define _PUSH_X_FRONT(...) X, __VA_ARGS__
/*
Returns the number of arguments specified.
#ifndef _MSC_VER
#define VA_NARGS(...) _VA_NARGS_IMPL2(X,##__VA_ARGS__)
*/
#define VA_NARGS(...) _VA_NARGS_IMPL2(_PUSH_X_FRONT(__VA_ARGS__))
// testing is gewd
static_assert(VA_NARGS() == 0, "VA_NARGS() failed for 0 arguments");
static_assert(VA_NARGS(one, two, three, four) == 4, "VA_NARGS() failed for 4 arguments");
#define _VARARG_IMPL2(N, Macro, ...) Macro##N(__VA_ARGS__)
#define _VARARG_IMPL(N, Macro, ...) _VARARG_IMPL2(N, Macro, __VA_ARGS__)
// Helper function for variadic macros with per-argument processing.
#define VARARG(Macro, ...) _VARARG_IMPL(VA_NARGS(__VA_ARGS__), Macro, __VA_ARGS__)
#define _Quote1(x) #x
#define _Quote2(x, ...) #x, _Quote1(__VA_ARGS__)
#define _Quote3(x, ...) #x, _Quote2(__VA_ARGS__)
#define _Quote4(x, ...) #x, _Quote3(__VA_ARGS__)
// Treat each argument as a string literal, encompassing in quotes.
#define Quote(...) VARARG(_Quote, __VA_ARGS__)
Question:
constexpr char *a[] = { Quote(a, b) };
// WHY does the above produce {"a, b"} with msvc?
// The following produces {"a", "b"} as expected
constexpr char *a[] = { _Quote2(s, c) };
It is difficult to make a real variadic macro to work in VS2013. I had something done to expand a macro to be interpreted on it's own as a new macro. The key is to make multiple level macros. It is a lot to code but for given sample it will work.
#define InitialMacro (argument1, argument2) \
DetailedMacro(argument1, argument2, argument1##_description, argument2##_description)
#define DetailedMacro (argument1, argument2, argument3, argument4) \
L#argument1 \
L#argument2 \
L#argument3 \
L#argument4
The ideea presented here is to implement enough macros to cover all your requirement in the number of parameters nedeed. Also you can forward/update macro with aditional items on the way.
Basically first macro in this example append to the second and third transmitted parameters the suffix _description resulting in another macro that will get interpreted as a macro and it will be expanded in DetailedMacro.
You could also take a look at this: msvc variadic macro expansion
I am trying to use the stringizing operator #, but I get the error stray ‘#’ in program. Here is how I am using it.
#define STR "SOME_STRING"
#define BM 8
#define NUM_OF_THREADS 8
#define VER_STR (STR #BM #NUM_THREADS)
I expect to get SOME_STRING88 for VER_STR but instead get an error. What mistake am I doing?
You need to turn the numerical constants into a string. However, #BM is an error, since the syntax is only valid for macro parameters.
So you need to force en expansion through an intermediate macro. And you may as well have a STRINGIFY macro to do it:
#include <iostream>
#define STRINGIFY_(x) #x
#define STRINGIFY(x) STRINGIFY_(x)
#define STR "SOME_STRING"
#define BM 8
#define S_BM STRINGIFY(BM)
#define NUM_OF_THREADS 8
#define S_NUM_OF_THREADS STRINGIFY(NUM_OF_THREADS)
#define VER_STR STR S_BM S_NUM_OF_THREADS
int main() {
// your code goes here
std::cout << VER_STR;
return 0;
}
You can see the above in action at http://ideone.com/cR1KZP
EDIT
As Magnus Hoff pointed out, you can invoke STRINGIFY directly as well:
#define VER_STR STR STRINGIFY(BM) STRINGIFY(NUM_OF_THREADS)
So I've got a macro that works nicely in GCC, but not in Microsoft's C++ Compiler. I'm hoping somebody might know of a workaround, or perhaps can explain to me why it behaves this way.
I'm sure this macro isn't exactly "standard", but it would really help me out.
Here is a functional example of the macro:
#define VA_NARGS_IMPL(_1, _2, _3, _4, _5, N, ...) N
#define VA_NARGS(...) VA_NARGS_IMPL(__VA_ARGS__, 5, 4, 3, 2, 1)
#define FULLY_EXPANDED(count, ...) \
MAC ## count (__VA_ARGS__)
#define SEMI_EXPANDED(count, ...) FULLY_EXPANDED(count, __VA_ARGS__)
#define EXPAND_THESE(...) SEMI_EXPANDED(VA_NARGS(__VA_ARGS__), __VA_ARGS__)
#define ACTUAL_MACRO(x) parent->GetProperty<x>();
#define MAC1(a) ACTUAL_MACRO(a)
#define MAC2(a,b) MAC1(a) ACTUAL_MACRO(b)
#define MAC3(a,b,c) MAC2(a,b) ACTUAL_MACRO(c)
#define MAC4(a,b,c,d) MAC3(a,b,c) ACTUAL_MACRO(d)
#define MAC5(a,b,c,d,e) MAC4(a,b,c,d) ACTUAL_MACRO(e)
Here is how I might use this macro:
struct MyStructure
{
void Foo()
{
EXPAND_THESE(Property1, Property2, Property3, Property4)
}
Base * parent;
}
Here's how GCC expands the above:
struct MyStructure
{
void Foo()
{
parent->GetProperty<Property1>();
parent->GetProperty<Property2>();
parent->GetProperty<Property3>();
parent->GetProperty<Property4>();
}
Base * parent;
}
But Microsoft for some reason expands all my __VA_ARGS__ as one argument:
struct MyStructure
{
void Foo()
{
parent->GetProperty<Property1, Property2, Property3, Property4>();
}
Base * parent;
}
Does anybody know why this is? Is there some trick I can pull to get Microsoft to expand this like GCC? Maybe toss in a couple extra pairs of parentheses?
Macros like this could really help me out in replacing a bunch of "glue" code, but because of this problem, I can't move it into my VS project. Any help would be greatly appreciated!
Thanks.
I know this question is over two years old, but I thought I would try to give a more polished answer to those who still stumble upon this, like I did.
Jeff Walden's answer works and all, but you have to declare FOO_CHOOSE_HELPER/1/2 for each FOO macro you want to have variadic arguments. I have developed a layer of abstraction to solve this issue. Consider the following:
#define GLUE(x, y) x y
#define RETURN_ARG_COUNT(_1_, _2_, _3_, _4_, _5_, count, ...) count
#define EXPAND_ARGS(args) RETURN_ARG_COUNT args
#define COUNT_ARGS_MAX5(...) EXPAND_ARGS((__VA_ARGS__, 5, 4, 3, 2, 1, 0))
#define OVERLOAD_MACRO2(name, count) name##count
#define OVERLOAD_MACRO1(name, count) OVERLOAD_MACRO2(name, count)
#define OVERLOAD_MACRO(name, count) OVERLOAD_MACRO1(name, count)
#define CALL_OVERLOAD(name, ...) GLUE(OVERLOAD_MACRO(name, COUNT_ARGS_MAX5(__VA_ARGS__)), (__VA_ARGS__))
With this architecture you can define variadic macros as such:
#define ERROR1(title) printf("Error: %s\n", title)
#define ERROR2(title, message)\
ERROR1(title);\
printf("Message: %s\n", message)
#define ERROR(...) CALL_OVERLOAD(ERROR, __VA_ARGS__)
#define ASSERT1(expr) singleArgumentExpansion(expr)
#define ASSERT2(expr, explain) twoArgumentExpansion(expr, explain)
#define ASSERT(...) CALL_OVERLOAD(ASSERT, __VA_ARGS__)
With Jeff's answer you would have to define the macros as follows:
#define ERROR1(title) printf("Error: %s\n", title)
#define ERROR2(title, message)\
ERROR1(title);\
printf("Message: %s\n", message)
#define ERROR_CHOOSE_HELPER2(count) ERROR##count
#define ERROR_CHOOSE_HELPER1(count) ERROR_CHOOSE_HELPER2(count)
#define ERROR_CHOOSE_HELPER(count) ERROR_CHOOSE_HELPER1(count)
#define ERROR(...) GLUE(ERROR_CHOOSE_HELPER(COUNT_ARGS_MAX5(__VA_ARGS__)),\
(__VA_ARGS__))
#define ASSERT1(expr) singleArgumentExpansion(expr)
#define ASSERT2(expr, explain) twoArgumentExpansion(expr, explain)
#define ASSERT_CHOOSE_HELPER2(count) ASSERT##count
#define ASSERT_CHOOSE_HELPER1(count) ASSERT_CHOOSE_HELPER2(count)
#define ASSERT_CHOOSE_HELPER(count) ASSERT_CHOOSE_HELPER1(count)
#define ASSERT(...) GLUE(ASSERT_CHOOSE_HELPER(COUNT_ARGS_MAX5(__VA_ARGS__)),\
(__VA_ARGS__))
It's not a big deal, however I like my code to be as concise as possible. It also helps exponentially, if you are using several variadic macros, to reduce code duplication and the complications that can cause. As far as I know, this method is also portable. I have tested it on many of the most common compilers and they produced the same results.
Example use:
int foo()
{
ASSERT(one); // singleArgumentExpansion(one)
ASSERT(two, "foopy"); // twoArgumentExpansion(two, "foopy")
ERROR("Only print a title");
ERROR("Error title", "Extended error description");
}
Coincidentally, I happened to run into this problem just today, and after enough effort I think I've found a solution for my own purposes. The bug is MSVC treats __VA_ARGS__ as a single token in argument lists. But you can work around this by not using it directly within a macro call argument list. This comment suggests the start of an answer to your problems:
#define VA_NARGS(...) VA_NUM_ARGS_IMPL_((__VA_ARGS__, 5,4,3,2,1))
#define VA_NARGS_IMPL_(tuple) VA_NUM_ARGS_IMPL tuple
#define VA_NARGS_IMPL(_1,_2,_3,_4,_5,N,...) N
But then I suspect you'll likely run into the issue of making sure that gets fully expanded to the actual "N" you want, and not to VA_NARGS_IMPL (arg1, arg2, 5, 4, 3, 2, 1), say. I found that my code (which looked like yours) had to change to expand MAC##code all as one unit, and then that had to be separately combined with the argument list. Here's the code that I found worked for me:
#define ASSERT_HELPER1(expr) singleArgumentExpansion(expr)
#define ASSERT_HELPER2(expr, explain) \
twoArgumentExpansion(expr, explain)
/*
* Count the number of arguments passed to ASSERT, very carefully
* tiptoeing around an MSVC bug where it improperly expands __VA_ARGS__ as a
* single token in argument lists. See these URLs for details:
*
* http://connect.microsoft.com/VisualStudio/feedback/details/380090/variadic-macro-replacement
* http://cplusplus.co.il/2010/07/17/variadic-macro-to-count-number-of-arguments/#comment-644
*/
#define COUNT_ASSERT_ARGS_IMPL2(_1, _2, count, ...) \
count
#define COUNT_ASSERT_ARGS_IMPL(args) \
COUNT_ASSERT_ARGS_IMPL2 args
#define COUNT_ASSERT_ARGS(...) \
COUNT_ASSERT_ARGS_IMPL((__VA_ARGS__, 2, 1, 0))
/* Pick the right helper macro to invoke. */
#define ASSERT_CHOOSE_HELPER2(count) ASSERT_HELPER##count
#define ASSERT_CHOOSE_HELPER1(count) ASSERT_CHOOSE_HELPER2(count)
#define ASSERT_CHOOSE_HELPER(count) ASSERT_CHOOSE_HELPER1(count)
/* The actual macro. */
#define ASSERT_GLUE(x, y) x y
#define ASSERT(...) \
ASSERT_GLUE(ASSERT_CHOOSE_HELPER(COUNT_ASSERT_ARGS(__VA_ARGS__)), \
(__VA_ARGS__))
int foo()
{
ASSERT(one); // singleArgumentExpansion(one)
ASSERT(two, "foopy"); // twoArgumentExpansion(two, "foopy")
}
My mind is too much mush after a few hours solving my own issues to then go and completely solve yours, I'm sorry to say. :-) But I think this is enough to get you to something that works, with a little work.
Microsoft has rewritten the C/C++ preprocessor, but it is not enabled by default for "backwards-compatibility", i.e. they prefer bug-compatibility with their own products instead of portability or standard compliance.
It seems that you can fix the __VA_ARGS__ handling by adding a /experimental:preprocessor flag to the command line.