MSVC Preprocessor Bug - Overloading C/C++ Macro on Argument Count [duplicate] - c++
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.
Related
Compilation seems to start before Preprocessor macro expansion
I am attempting to create a C++ DLL to export, and I need to export all functions of a class. So I came up with this idea to cut out the boilerplate: #define CONCATENATE_WRAPPED(arg1, arg2) CONCATENATE_WRAPPED_1(arg1, arg2) #define CONCATENATE_WRAPPED_1(arg1, arg2) CONCATENATE_WRAPPED_2(arg1, arg2) #define CONCATENATE_WRAPPED_2(arg1, arg2) CONCATENATE_WRAPPED_3(arg1, arg2) #define CONCATENATE_WRAPPED_3(arg1, arg2) CONCATENATE_WRAPPED_4(arg1, arg2) #define CONCATENATE_WRAPPED_4(arg1, arg2) arg1##arg2 // Counts the number of pairs: #define PAIR_SEQUENCER(_1, _1x, _2, _2x, _3, _3x, _4, _4x, N, ...) N #define COUNT_PAIRS(...) PAIR_SEQUENCER(__VA_ARGS__, 4, x, 3, x, 2, x, 1, 0, 0, x) // Internal for declaring arguments: #define DECLARE_ARGUMENTS_0(...) #define DECLARE_ARGUMENTS_1(typeName, varName, ...)\ typeName varName #define DECLARE_ARGUMENTS_2(typeName, varName, ...)\ typeName varName,\ DECLARE_ARGUMENTS_1(__VA_ARGS__) #define DECLARE_ARGUMENTS_3(typeName, varName, ...)\ typeName varName,\ DECLARE_ARGUMENTS_2(__VA_ARGS__) // Internal for passing arguments: #define PASS_ARGUMENTS_0(...) #define PASS_ARGUMENTS_1(typeName, varName, ...)\ varName\ PASS_ARGUMENTS_0(__VA_ARGS__) #define PASS_ARGUMENTS_2(typeName, varName, ...)\ varName, \ PASS_ARGUMENTS_1(__VA_ARGS__) #define PASS_ARGUMENTS_3(typeName, varName, ...)\ varName, \ PASS_ARGUMENTS_2(__VA_ARGS__) // Macro to call when declaring parameters and will adjust depending on the number of params, so that // DECLARE_ARGUMENTS(int, a, float, b) expands to (int a, float b) for up to three pairs. #define DECLARE_ARGUMENTS(...) ( CONCATENATE_WRAPPED(DECLARE_ARGUMENTS_, COUNT_PAIRS(__VA_ARGS__))(__VA_ARGS__) )) // Macro to call when passing parameters and will adjust depending on the number of params, so that // PASS_ARGUMENTS(int, a, float, b) expands to (a, b) for up to three pairs. #define PASS_ARGUMENTS(...) ( CONCATENATE_WRAPPED(PASS_ARGUMENTS_, COUNT_PAIRS(__VA_ARGS__))(__VA_ARGS__) ) With all this context out of the way, this is what my main macro looks like: #define IMPLEMENT_CONSTRUCTOR(typeName, functionName, ...) \ extern "C" __declspec(dllexport) typeName* __stdcall functionName DECLARE_ARGUMENTS(__VA_ARGS__) \ { \ return new typeName PASS_ARGUMENTS(__VA_ARGS__); \ } \ typeName::typeName DECLARE_ARGUMENTS(__VA_ARGS__) // the intention is so that IMPLEMENT_CONSTRUCTOR(MacroTestObject, CreateMacroTestObjectWithTwoParams, int, TwoParamFirst, float, TwoParamSecond) { } //expands to extern "C" __declspec(dllexport) MacroTestObject* __stdcall CreateMacroTestObjectWithTwoParams(int TwoParamFirst, float TwoParamSecond) { return new MacroTestObject(TwoParamFirst, TwoParamSecond); } MacroTestObject::MacroTestObject(int TwoParamFirst, float TwoParamSecond) { } But the problem seems to be that the C++ compiler starts compiling even before all the macros have expanded, which throws out compile-time errors like crazy, showing something like: 0><Project>\MacroTestObject.cpp(4,1): Error C2512 : 'MacroTestObject::MacroTestObject': no appropriate default constructor available 0><Project>\MacroTestObject.cpp(5,1): Error C2511 : 'MacroTestObject::MacroTestObject(void)': overloaded member function not found in 'MacroTestObject' But when I use (Rider for Unreal Engine)'s "Substitute macro calls and all nested calls" function, the macro expands out just fine. Can someone help me out with this, I don't know why this is happening and I can't seem to find any particular assistance online. This DLL is meant to be used in Unity3D as a native plug-in and so as far as I know using C++/CLI is out of the question. I don't think COM interop is an option either because all the info I read about it implies that I need to create TLB files, and since Unity handles C# compilation, that seems out of the question too. EDIT: I think I kind of figured out why this is causing issues. // Something like COUNT_PAIRS(a, b, c, d, e, f) // always expands to 0 // because __VA_ARGS__ is considered as a single argument // and a recount is not triggered. I tried using CONCATENATE_WRAPPED // in different places but unfortunately it has been no help. Could someone help me out with this? Edit 2: Solved the problem, switched to Clang. Also, there's an extra bracket in DECLARE_ARGUMENTS macro.
So I think this version should now work as you would want. I've found two problems: The already mentioned additional ")" in DECLARE_ARGUMENT, that was an easy fix The fact that MSVC seems to trat __VA_ARGS__ differently than gcc and clang, it doesn't expand the arguments into themselves but treats it one. That's why e.g. COUNT_PAIRS didn't work correctly. The fix is taken from this SO Question I suggest playing around with it a bit in godbolt to see how it works ;) Hope this solves your problem EDIT: I also just saw here that Visual Studio has apparently updated their preprocessor, so depending on which version one is using it could be possible to avoid all the ugly EXPAND calls by using the compiler switch /Zc:preprocessor
Ignoring MACRO argument [duplicate]
Is there some way of getting optional parameters with C++ Macros? Some sort of overloading would be nice too.
Here's one way to do it. It uses the list of arguments twice, first to form the name of the helper macro, and then to pass the arguments to that helper macro. It uses a standard trick to count the number of arguments to a macro. enum { plain = 0, bold = 1, italic = 2 }; void PrintString(const char* message, int size, int style) { } #define PRINT_STRING_1_ARGS(message) PrintString(message, 0, 0) #define PRINT_STRING_2_ARGS(message, size) PrintString(message, size, 0) #define PRINT_STRING_3_ARGS(message, size, style) PrintString(message, size, style) #define GET_4TH_ARG(arg1, arg2, arg3, arg4, ...) arg4 #define PRINT_STRING_MACRO_CHOOSER(...) \ GET_4TH_ARG(__VA_ARGS__, PRINT_STRING_3_ARGS, \ PRINT_STRING_2_ARGS, PRINT_STRING_1_ARGS, ) #define PRINT_STRING(...) PRINT_STRING_MACRO_CHOOSER(__VA_ARGS__)(__VA_ARGS__) int main(int argc, char * const argv[]) { PRINT_STRING("Hello, World!"); PRINT_STRING("Hello, World!", 18); PRINT_STRING("Hello, World!", 18, bold); return 0; } This makes it easier for the caller of the macro, but not the writer.
With great respect to Derek Ledbetter for his answer — and with apologies for reviving an old question. Getting an understanding of what it was doing and picking up elsewhere on the ability to preceed the __VA_ARGS__ with ## allowed me to come up with a variation... // The multiple macros that you would need anyway [as per: Crazy Eddie] #define XXX_0() <code for no arguments> #define XXX_1(A) <code for one argument> #define XXX_2(A,B) <code for two arguments> #define XXX_3(A,B,C) <code for three arguments> #define XXX_4(A,B,C,D) <code for four arguments> // The interim macro that simply strips the excess and ends up with the required macro #define XXX_X(x,A,B,C,D,FUNC, ...) FUNC // The macro that the programmer uses #define XXX(...) XXX_X(,##__VA_ARGS__,\ XXX_4(__VA_ARGS__),\ XXX_3(__VA_ARGS__),\ XXX_2(__VA_ARGS__),\ XXX_1(__VA_ARGS__),\ XXX_0(__VA_ARGS__)\ ) For non-experts like me who stumble upon the answer, but can't quite see how it works, I'll step through the actual processing, starting with the following code... XXX(); XXX(1); XXX(1,2); XXX(1,2,3); XXX(1,2,3,4); XXX(1,2,3,4,5); // Not actually valid, but included to show the process Becomes... XXX_X(, XXX_4(), XXX_3(), XXX_2(), XXX_1(), XXX_0() ); XXX_X(, 1, XXX_4(1), XXX_3(1), XXX_2(1), XXX_1(1), XXX_0(1) ); XXX_X(, 1, 2, XXX_4(1,2), XXX_3(1,2), XXX_2(1,2), XXX_1(1,2), XXX_0(1,2) ); XXX_X(, 1, 2, 3, XXX_4(1,2,3), XXX_3(1,2,3), XXX_2(1,2,3), XXX_1(1,2,3), XXX_0(1,2,3) ); XXX_X(, 1, 2, 3, 4, XXX_4(1,2,3,4), XXX_3(1,2,3,4), XXX_2(1,2,3,4), XXX_1(1,2,3,4), XXX_0(1,2,3,4) ); XXX_X(, 1, 2, 3, 4, 5, XXX_4(1,2,3,4,5), XXX_3(1,2,3,4,5), XXX_2(1,2,3,4,5), XXX_1(1,2,3,4,5), XXX_0(1,2,3,4,5) ); Which becomes just the sixth argument... XXX_0(); XXX_1(1); XXX_2(1,2); XXX_3(1,2,3); XXX_4(1,2,3,4); 5; PS: Remove the #define for XXX_0 to get a compile error [ie: if a no-argument option is not allowed]. PPS: Would be nice to have the invalid situations (eg: 5) be something that gives a clearer compilation error to the programmer! PPPS: I'm not an expert, so I'm very happy to hear comments (good, bad or other)!
With greatest respect to Derek Ledbetter, David Sorkovsky, Syphorlate for their answers, together with the ingenious method to detect empty macro arguments by Jens Gustedt at https://gustedt.wordpress.com/2010/06/08/detect-empty-macro-arguments/ finally I come out with something that incorporates all the tricks, so that the solution Uses only standard C99 macros to achieve function overloading, no GCC/CLANG/MSVC extension involved (i.e., comma swallowing by the specific expression , ##__VA_ARGS__ for GCC/CLANG, and implicit swallowing by ##__VA_ARGS__ for MSVC). So feel free to pass the missing --std=c99 to your compiler if you wish =) Works for zero argument, as well as unlimited number of arguments, if you expand it further to suit your needs Works reasonably cross-platform, at least tested for GNU/Linux + GCC (GCC 4.9.2 on CentOS 7.0 x86_64) GNU/Linux + CLANG/LLVM, (CLANG/LLVM 3.5.0 on CentOS 7.0 x86_64) OS X + Xcode, (XCode 6.1.1 on OS X Yosemite 10.10.1) Windows + Visual Studio, (Visual Studio 2013 Update 4 on Windows 7 SP1 64 bits) For the lazies, just skip to the very last of this post to copy the source. Below is the detailed explanation, which hopefully helps and inspires all people looking for the general __VA_ARGS__ solutions like me. =) Here's how it goes. First define the user-visible overloaded "function", I named it create, and the related actual function definition realCreate, and the macro definitions with different number of arguments CREATE_2, CREATE_1, CREATE_0, as shown below: #define create(...) MACRO_CHOOSER(__VA_ARGS__)(__VA_ARGS__) void realCreate(int x, int y) { printf("(%d, %d)\n", x, y); } #define CREATE_2(x, y) realCreate(x, y) #define CREATE_1(x) CREATE_2(x, 0) #define CREATE_0() CREATE_1(0) The MACRO_CHOOSER(__VA_ARGS__) part ultimately resolves to the macro definition names, and the second (__VA_ARGS__) part comprises their parameter lists. So a user's call to create(10) resolves to CREATE_1(10), the CREATE_1 part comes from MACRO_CHOOSER(__VA_ARGS__), and the (10) part comes from the second (__VA_ARGS__). The MACRO_CHOOSER uses the trick that, if __VA_ARGS__ is empty, the following expression is concatenated into a valid macro call by the preprocessor: NO_ARG_EXPANDER __VA_ARGS__ () // simply shrinks to NO_ARG_EXPANDER() Ingeniusly, we can define this resulting macro call as #define NO_ARG_EXPANDER() ,,CREATE_0 Note the two commas, they are explained soon. The next useful macro is #define MACRO_CHOOSER(...) CHOOSE_FROM_ARG_COUNT(NO_ARG_EXPANDER __VA_ARGS__ ()) so the calls of create(); create(10); create(20, 20); are actually expanded to CHOOSE_FROM_ARG_COUNT(,,CREATE_0)(); CHOOSE_FROM_ARG_COUNT(NO_ARG_EXPANDER 10 ())(10); CHOOSE_FROM_ARG_COUNT(NO_ARG_EXPANDER 20, 20 ())(20, 20); As the macro name suggests, we are to count number of arguments later. Here comes another trick: the preprocessor only does simple text replacement. It infers the number of arguments of a macro call merely from the number of commas it sees inside the parentheses. The actual "arguments" separated by commas need not to be of valid syntax. They can be any text. That's to say, in the above example, NO_ARG_EXPANDER 10 () is counted as 1 argument for the middle call. NO_ARG_EXPANDER 20 and 20 () are counted as 2 arguments for the bottom call respectively. If we use the following helper macros to further expand them ##define CHOOSE_FROM_ARG_COUNT(...) \ FUNC_RECOMPOSER((__VA_ARGS__, CREATE_2, CREATE_1, )) #define FUNC_RECOMPOSER(argsWithParentheses) \ FUNC_CHOOSER argsWithParentheses The trailing , after CREATE_1 is a work-around for GCC/CLANG, suppressing a (false positive) error saying that ISO C99 requires rest arguments to be used when passing -pedantic to your compiler. The FUNC_RECOMPOSER is a work-around for MSVC, or it can not count number of arguments (i.e., commas) inside the parentheses of macro calls correctly. The results are further resolved to FUNC_CHOOSER (,,CREATE_0, CREATE_2, CREATE_1, )(); FUNC_CHOOSER (NO_ARG_EXPANDER 10 (), CREATE_2, CREATE_1, )(10); FUNC_CHOOSER (NO_ARG_EXPANDER 20, 20 (), CREATE_2, CREATE_1, )(20, 20); As the eagle-eyed you may have seen, the last only step we need is to employ a standard argument counting trick to finally pick the wanted macro version names: #define FUNC_CHOOSER(_f1, _f2, _f3, ...) _f3 which resolves the results to CREATE_0(); CREATE_1(10); CREATE_2(20, 20); and certainly gives us the desired, actual function calls: realCreate(0, 0); realCreate(10, 10); realCreate(20, 20); Putting all together, with some rearrangement of statements for better readability, the whole source of the 2-argument example is here: #include <stdio.h> void realCreate(int x, int y) { printf("(%d, %d)\n", x, y); } #define CREATE_2(x, y) realCreate(x, y) #define CREATE_1(x) CREATE_2(x, 0) #define CREATE_0() CREATE_1(0) #define FUNC_CHOOSER(_f1, _f2, _f3, ...) _f3 #define FUNC_RECOMPOSER(argsWithParentheses) FUNC_CHOOSER argsWithParentheses #define CHOOSE_FROM_ARG_COUNT(...) FUNC_RECOMPOSER((__VA_ARGS__, CREATE_2, CREATE_1, )) #define NO_ARG_EXPANDER() ,,CREATE_0 #define MACRO_CHOOSER(...) CHOOSE_FROM_ARG_COUNT(NO_ARG_EXPANDER __VA_ARGS__ ()) #define create(...) MACRO_CHOOSER(__VA_ARGS__)(__VA_ARGS__) int main() { create(); create(10); create(20, 20); //create(30, 30, 30); // Compilation error return 0; } Although complicated, ugly, burdening the API developer, there comes a solution for overloading and setting optional parameters of C/C++ functions to us crazy people. The usage of the out-coming overloaded APIs become very enjoyable and pleasant. =) If there is any further possible simplification of this approach, please do let me know at https://github.com/jason-deng/C99FunctionOverload Again special thanks to all of the brilliant people that inspired and led me to achieve this piece of work! =)
C++ macros haven't changed from C. Since C didn't have overloading and default arguments for functions, it certainly didn't have them for macros. So to answer your question: no, those features don't exist for macros. Your only option is to define multiple macros with different names (or not use macros at all). As a sidenote: In C++ it's generally considered good practice to move away from macros as much as possible. If you need features like this, there's a good chance you're overusing macros.
For anyone painfully searching some VA_NARGS solution that works with Visual C++. Following macro worked for me flawlessly(also with zero parameters!) in visual c++ express 2010: #define VA_NUM_ARGS_IMPL(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,_21,_22,_23,_24,N,...) N #define VA_NUM_ARGS_IMPL_(tuple) VA_NUM_ARGS_IMPL tuple #define VA_NARGS(...) bool(#__VA_ARGS__) ? (VA_NUM_ARGS_IMPL_((__VA_ARGS__, 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 If you want a macro with optional parameters you can do: //macro selection(vc++) #define SELMACRO_IMPL(_1,_2,_3, N,...) N #define SELMACRO_IMPL_(tuple) SELMACRO_IMPL tuple #define mymacro1(var1) var1 #define mymacro2(var1,var2) var2*var1 #define mymacro3(var1,var2,var3) var1*var2*var3 #define mymacro(...) SELMACRO_IMPL_((__VA_ARGS__, mymacro3(__VA_ARGS__), mymacro2(__VA_ARGS__), mymacro1(__VA_ARGS__))) That worked for me aswell in vc. But it doesn't work for zero parameters. int x=99; x=mymacro(2);//2 x=mymacro(2,2);//4 x=mymacro(2,2,2);//8
gcc/g++ supports varargs macros but I don't think this is standard, so use it at your own risk.
More concise version of Derek Ledbetter's code: enum { plain = 0, bold = 1, italic = 2 }; void PrintString(const char* message = NULL, int size = 0, int style = 0) { } #define PRINT_STRING(...) PrintString(__VA_ARGS__) int main(int argc, char * const argv[]) { PRINT_STRING("Hello, World!"); PRINT_STRING("Hello, World!", 18); PRINT_STRING("Hello, World!", 18, bold); return 0; }
#include <stdio.h> #define PP_NARG(...) \ PP_NARG_(__VA_ARGS__,PP_RSEQ_N()) #define PP_NARG_(...) \ PP_ARG_N(__VA_ARGS__) #define PP_ARG_N( \ _1, _2, _3, _4, _5, _6, _7, _8, _9,_10, \ _11,_12,_13,_14,_15,_16,_17,_18,_19,_20, \ _21,_22,_23,_24,_25,_26,_27,_28,_29,_30, \ _31,_32,_33,_34,_35,_36,_37,_38,_39,_40, \ _41,_42,_43,_44,_45,_46,_47,_48,_49,_50, \ _51,_52,_53,_54,_55,_56,_57,_58,_59,_60, \ _61,_62,_63,N,...) N #define PP_RSEQ_N() \ 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 #define PP_CONCAT(a,b) PP_CONCAT_(a,b) #define PP_CONCAT_(a,b) a ## b #define THINK(...) PP_CONCAT(THINK_, PP_NARG(__VA_ARGS__))(__VA_ARGS__) #define THINK_0() THINK_1("sector zz9 plural z alpha") #define THINK_1(location) THINK_2(location, 42) #define THINK_2(location,answer) THINK_3(location, answer, "deep thought") #define THINK_3(location,answer,computer) \ printf ("The answer is %d. This was calculated by %s, and a computer to figure out what this" " actually means will be build in %s\n", (answer), (computer), (location)) int main (int argc, char *argv[]) { THINK (); /* On compilers other than GCC you have to call with least one non-default argument */ } DISCLAIMER: Mostly harmless.
As a big fan of horrible macro monsters, I wanted to expand on Jason Deng's answer and make it actually usable. (For better or worse.) The original is not very nice to use because you need to modify the big alphabet soup every time you want to make a new macro and it's even worse if you need different amount of arguments. So I made a version with these features: 0 argument case works 1 to 16 arguments without any modifications to the messy part Easy to write more macro functions Tested in gcc 10, clang 9, Visual Studio 2017 Currently I just made 16 argument maximum, but if you need more (really now? you're just getting silly...) you can edit FUNC_CHOOSER and CHOOSE_FROM_ARG_COUNT, then add some commas to NO_ARG_EXPANDER. Please see Jason Deng's excellent answer for more details on the implementation, but I'll just put the code here: #include <stdio.h> void realCreate(int x, int y) { printf("(%d, %d)\n", x, y); } // This part you put in some library header: #define FUNC_CHOOSER(_f0, _f1, _f2, _f3, _f4, _f5, _f6, _f7, _f8, _f9, _f10, _f11, _f12, _f13, _f14, _f15, _f16, ...) _f16 #define FUNC_RECOMPOSER(argsWithParentheses) FUNC_CHOOSER argsWithParentheses #define CHOOSE_FROM_ARG_COUNT(F, ...) FUNC_RECOMPOSER((__VA_ARGS__, \ F##_16, F##_15, F##_14, F##_13, F##_12, F##_11, F##_10, F##_9, F##_8,\ F##_7, F##_6, F##_5, F##_4, F##_3, F##_2, F##_1, )) #define NO_ARG_EXPANDER(FUNC) ,,,,,,,,,,,,,,,,FUNC ## _0 #define MACRO_CHOOSER(FUNC, ...) CHOOSE_FROM_ARG_COUNT(FUNC, NO_ARG_EXPANDER __VA_ARGS__ (FUNC)) #define MULTI_MACRO(FUNC, ...) MACRO_CHOOSER(FUNC, __VA_ARGS__)(__VA_ARGS__) // When you need to make a macro with default arguments, use this: #define create(...) MULTI_MACRO(CREATE, __VA_ARGS__) #define CREATE_0() CREATE_1(0) #define CREATE_1(x) CREATE_2(x, 0) #define CREATE_2(x, y) \ do { \ /* put whatever code you want in the last macro */ \ realCreate(x, y); \ } while(0) int main() { create(); create(10); create(20, 20); //create(30, 30, 30); // Compilation error return 0; }
That's not really what the preprocessor is designed for. That said, if you want to enter into the area of seriously challenging macro programming with a modicum of readability, you should take a look at the Boost preprocessor library. After all, it wouldn't be C++ if there weren't three completely Turing compatible levels of programming (preprocessor, template metaprogramming, and base level C++)!
#define MY_MACRO_3(X,Y,Z) ... #define MY_MACRO_2(X,Y) MY_MACRO(X,Y,5) #define MY_MACRO_1(X) MY_MACRO(X,42,5) You know at the point of call how many args you're going to pass in so there's really no need for overloading.
You can use BOOST_PP_OVERLOAD from a boost library. Example from official boost doc: #include <boost/preprocessor/facilities/overload.hpp> #include <boost/preprocessor/cat.hpp> #include <boost/preprocessor/facilities/empty.hpp> #include <boost/preprocessor/arithmetic/add.hpp> #define MACRO_1(number) MACRO_2(number,10) #define MACRO_2(number1,number2) BOOST_PP_ADD(number1,number2) #if !BOOST_PP_VARIADICS_MSVC #define MACRO_ADD_NUMBERS(...) BOOST_PP_OVERLOAD(MACRO_,__VA_ARGS__)(__VA_ARGS__) #else // or for Visual C++ #define MACRO_ADD_NUMBERS(...) \ BOOST_PP_CAT(BOOST_PP_OVERLOAD(MACRO_,__VA_ARGS__)(__VA_ARGS__),BOOST_PP_EMPTY()) #endif MACRO_ADD_NUMBERS(5) // output is 15 MACRO_ADD_NUMBERS(3,6) // output is 9
Depending on what you need, you could do it with var args with macros. Now, optional parameters or macro overloading, there is no such thing.
Not directly answering the question, but using the same trick as David Sorkovsky answer and giving a clear example of how to build complex macros. Just compile this with g++ -E test.cpp -o test && cat test: // #define GET_FIRST_ARG_0_ARGS(default) (default) // #define GET_FIRST_ARG_1_ARGS(default, a) (a) // #define GET_FIRST_ARG_2_ARGS(default, a, b) (a) // #define GET_FIRST_ARG_3_ARGS(default, a, b, c) (a) // #define GET_FIRST_ARG_4_ARGS(default, a, b, c, d) (a) #define GET_FIRST_ARG_MACROS(default, a, b, c, d, macro, ...) macro #define GET_FIRST_ARG(default, ...) GET_FIRST_ARG_MACROS( \ ,##__VA_ARGS__, \ GET_FIRST_ARG_4_ARGS(default, __VA_ARGS__), \ GET_FIRST_ARG_3_ARGS(default, __VA_ARGS__), \ GET_FIRST_ARG_2_ARGS(default, __VA_ARGS__), \ GET_FIRST_ARG_1_ARGS(default, __VA_ARGS__), \ GET_FIRST_ARG_0_ARGS(default, ##__VA_ARGS__), \ ) "0,"; GET_FIRST_ARG(0); "0,1"; GET_FIRST_ARG(0,1); "0,1,2"; GET_FIRST_ARG(0,1,2); "0,1,2,3"; GET_FIRST_ARG(0,1,2,3); "0,1,2,3,4"; GET_FIRST_ARG(0,1,2,3,4); To see the output: # 1 "test.cpp" # 1 "<built-in>" # 1 "<command-line>" # 1 "/usr/x86_64-linux-gnu/include/stdc-predef.h" 1 3 # 1 "<command-line>" 2 # 1 "test.cpp" # 16 "test.cpp" "0,"; GET_FIRST_ARG_0_ARGS(0); "0,1"; GET_FIRST_ARG_1_ARGS(0, 1); "0,1,2"; GET_FIRST_ARG_2_ARGS(0, 1,2); "0,1,2,3"; GET_FIRST_ARG_3_ARGS(0, 1,2,3); "0,1,2,3,4"; GET_FIRST_ARG_4_ARGS(0, 1,2,3,4); Now, a full working program would be: #include <iostream> #define GET_FIRST_ARG_0_ARGS(default) (default) #define GET_FIRST_ARG_1_ARGS(default, a) (a) #define GET_FIRST_ARG_2_ARGS(default, a, b) (a) #define GET_FIRST_ARG_3_ARGS(default, a, b, c) (a) #define GET_FIRST_ARG_4_ARGS(default, a, b, c, d) (a) #define GET_FIRST_ARG_MACROS(default, a, b, c, d, macro, ...) macro #define GET_FIRST_ARG(default, ...) GET_FIRST_ARG_MACROS( \ ,##__VA_ARGS__, \ GET_FIRST_ARG_4_ARGS(default, __VA_ARGS__), \ GET_FIRST_ARG_3_ARGS(default, __VA_ARGS__), \ GET_FIRST_ARG_2_ARGS(default, __VA_ARGS__), \ GET_FIRST_ARG_1_ARGS(default, __VA_ARGS__), \ GET_FIRST_ARG_0_ARGS(default, ##__VA_ARGS__), \ ) int main(int argc, char const *argv[]) { "0,"; GET_FIRST_ARG(0); "0,1"; GET_FIRST_ARG(0,1); "0,1,2"; GET_FIRST_ARG(0,1,2); "0,1,2,3"; GET_FIRST_ARG(0,1,2,3); "0,1,2,3,4"; GET_FIRST_ARG(0,1,2,3,4); std::cerr << "0, == " << GET_FIRST_ARG(0) << std::endl; std::cerr << "0,1 == " << GET_FIRST_ARG(0,1) << std::endl; std::cerr << "0,1,2 == " << GET_FIRST_ARG(0,1,2) << std::endl; std::cerr << "0,1,2,3 == " << GET_FIRST_ARG(0,1,2,3) << std::endl; std::cerr << "0,1,2,3,4 == " << GET_FIRST_ARG(0,1,2,3,4) << std::endl; return 0; } Which would output the following by being compiled with g++ test.cpp -o test && ./test: 0, == 0 0,1 == 1 0,1,2 == 1 0,1,2,3 == 1 0,1,2,3,4 == 1 Note: It is important to use () around the macro contents as #define GET_FIRST_ARG_1_ARGS(default, a) (a) to not break in ambiguous expressions when a is just not a integer. Extra macro for second argument: #define GET_SECOND_ARG_0_ARGS(default) (default) #define GET_SECOND_ARG_1_ARGS(default, a) (default) #define GET_SECOND_ARG_2_ARGS(default, a, b) (b) #define GET_SECOND_ARG_3_ARGS(default, a, b, c) (b) #define GET_SECOND_ARG_4_ARGS(default, a, b, c, d) (b) #define GET_SECOND_ARG_MACROS(default, a, b, c, d, macro, ...) macro #define GET_SECOND_ARG(default, ...) GET_SECOND_ARG_MACROS( \ ,##__VA_ARGS__, \ GET_SECOND_ARG_4_ARGS(default, __VA_ARGS__), \ GET_SECOND_ARG_3_ARGS(default, __VA_ARGS__), \ GET_SECOND_ARG_2_ARGS(default, __VA_ARGS__), \ GET_SECOND_ARG_1_ARGS(default, __VA_ARGS__), \ GET_SECOND_ARG_0_ARGS(default, ##__VA_ARGS__), \ )
None of the above examples (from Derek Ledbetter, David Sorkovsky, and Joe D) to count arguments with macros worked for me using Microsoft VCC 10. The __VA_ARGS__ argument is always considered as a single argument (token-izing it with ## or not), so the argument shifting in which those examples rely doesn't work. So, short answer, as stated by many others above: no, you can't overload macros or use optional arguments on them.
C++: Process each variadic argument in Visual Studio
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
MSVC++ variadic macro expansion
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.
Is C++ preprocessor metaprogramming Turing-complete?
I know C++ template metaprogramming is Turing-complete. Does the same thing hold for preprocessor metaprogramming?
Well macros don't directly expand recursively, but there are ways we can work around this. The easiest way of doing recursion in the preprocessor is to use a deferred expression. A deferred expression is an expression that requires more scans to fully expand: #define EMPTY() #define DEFER(id) id EMPTY() #define OBSTRUCT(...) __VA_ARGS__ DEFER(EMPTY)() #define EXPAND(...) __VA_ARGS__ #define A() 123 A() // Expands to 123 DEFER(A)() // Expands to A () because it requires one more scan to fully expand EXPAND(DEFER(A)()) // Expands to 123, because the EXPAND macro forces another scan Why is this important? Well when a macro is scanned and expanding, it creates a disabling context. This disabling context will cause a token, that refers to the currently expanding macro, to be painted blue. Thus, once its painted blue, the macro will no longer expand. This is why macros don't expand recursively. However, a disabling context only exists during one scan, so by deferring an expansion we can prevent our macros from becoming painted blue. We will just need to apply more scans to the expression. We can do that using this EVAL macro: #define EVAL(...) EVAL1(EVAL1(EVAL1(__VA_ARGS__))) #define EVAL1(...) EVAL2(EVAL2(EVAL2(__VA_ARGS__))) #define EVAL2(...) EVAL3(EVAL3(EVAL3(__VA_ARGS__))) #define EVAL3(...) EVAL4(EVAL4(EVAL4(__VA_ARGS__))) #define EVAL4(...) EVAL5(EVAL5(EVAL5(__VA_ARGS__))) #define EVAL5(...) __VA_ARGS__ Now if we want to implement a REPEAT macro using recursion, first we need some increment and decrement operators to handle state: #define CAT(a, ...) PRIMITIVE_CAT(a, __VA_ARGS__) #define PRIMITIVE_CAT(a, ...) a ## __VA_ARGS__ #define INC(x) PRIMITIVE_CAT(INC_, x) #define INC_0 1 #define INC_1 2 #define INC_2 3 #define INC_3 4 #define INC_4 5 #define INC_5 6 #define INC_6 7 #define INC_7 8 #define INC_8 9 #define INC_9 9 #define DEC(x) PRIMITIVE_CAT(DEC_, x) #define DEC_0 0 #define DEC_1 0 #define DEC_2 1 #define DEC_3 2 #define DEC_4 3 #define DEC_5 4 #define DEC_6 5 #define DEC_7 6 #define DEC_8 7 #define DEC_9 8 Next we need a few more macros to do logic: #define CHECK_N(x, n, ...) n #define CHECK(...) CHECK_N(__VA_ARGS__, 0,) #define NOT(x) CHECK(PRIMITIVE_CAT(NOT_, x)) #define NOT_0 ~, 1, #define COMPL(b) PRIMITIVE_CAT(COMPL_, b) #define COMPL_0 1 #define COMPL_1 0 #define BOOL(x) COMPL(NOT(x)) #define IIF(c) PRIMITIVE_CAT(IIF_, c) #define IIF_0(t, ...) __VA_ARGS__ #define IIF_1(t, ...) t #define IF(c) IIF(BOOL(c)) #define EAT(...) #define EXPAND(...) __VA_ARGS__ #define WHEN(c) IF(c)(EXPAND, EAT) Now with all these macros we can write a recursive REPEAT macro. We use a REPEAT_INDIRECT macro to refer back to itself recursively. This prevents the macro from being painted blue, since it will expand on a different scan(and using a different disabling context). We use OBSTRUCT here, which will defer the expansion twice. This is necessary because the conditional WHEN applies one scan already. #define REPEAT(count, macro, ...) \ WHEN(count) \ ( \ OBSTRUCT(REPEAT_INDIRECT) () \ ( \ DEC(count), macro, __VA_ARGS__ \ ) \ OBSTRUCT(macro) \ ( \ DEC(count), __VA_ARGS__ \ ) \ ) #define REPEAT_INDIRECT() REPEAT //An example of using this macro #define M(i, _) i EVAL(REPEAT(8, M, ~)) // 0 1 2 3 4 5 6 7 Now this example is limited to 10 repeats, because of limitations of the counter. Just like a repeat counter in a computer would be limited by the finite memory. Multiple repeat counters could be combined together to workaround this limitation, just like in a computer. Furthermore, we could define a FOREVER macro: #define FOREVER() \ ? \ DEFER(FOREVER_INDIRECT) () () #define FOREVER_INDIRECT() FOREVER // Outputs question marks forever EVAL(FOREVER()) This will try to output ? forever, but will eventually stop because there are no more scans being applied. Now the question is, if we gave it an infinite number of scans would this algorithm complete? This is known as the halting problem, and Turing completeness is necessary to prove the undecidability of the halting problem. So as you can see, the preprocessor can act as a Turing complete language, but instead of being limited to the finite memory of a computer it is instead limited by the finite number of scans applied.
No. The C++ preprocessor does not allow for unlimited state. You only have a finite number of on/off states, plus a include stack. This makes it a push-down automaton, not a turing machine (this ignores also the fact that preprocessor recursion is limited - but so is template recursion). However, if you bend your definitions a bit, this is possible by invoking the preprocessor multiple times - by allowing the preprocessor to generate a program which re-invokes the preprocessor, and looping externally, it is indeed possible to make a turing machine with the preprocessor. The linked example uses C, but it should be adaptable into C++ easily enough.