Reputation: 38919
I want to be able to generate these options from a macro:
if(void* temp = func(arg)){ foo(temp, variable);return; }
if(void* temp = func2(arg)){ foo(temp, variable2);return; }
if(void* temp = func3(arg)){ foo(temp, variable3);return; }
And so on, but as you can see 1 is the only special case.
I want to write a macro which takes in a number as a parameter and generates a line this code, potentially with numbers far greater than 3. Unfortunately this requires building in the special case if the user passed a 1 and exercising the general case if they passed any other number. Is there a way to do this?
Upvotes: 2
Views: 830
Reputation: 2664
If you really want to use the CPP for this, it's easy enough. An indirect GLUE
and an indirect SECOND
macro are core tools that you could use:
#define GLUE(A,B) GLUE_I(A,B)
#define GLUE_I(A,B) A##B
#define SECOND(...) SECOND_I(__VA_ARGS__,,)
#define SECOND_I(_,X,...) X
The indirect SECOND
allows you to pattern match in the preprocessor. The way that works is that you build a first token, which is normally just a throwaway. But since expansion is indirect, if that first token you build is a macro, it will expand first (namely, as part of argument substitution for the variadic). If that expansion contains a comma, it can shift in a "new" second argument right before the indirection picks the second one. You can use that to build your special cases.
Here's a cpp pattern matcher using this construct that returns its argument unless it is 1, in which case it expands to no tokens:
#define NOT_ONE(N) SECOND(GLUE(TEST_IF_1_IS_,N),N)
#define TEST_IF_1_IS_1 ,
Using that, your macro might be:
#define DISPATCH_CASE(N) \
if(void* temp = GLUE(func,NOT_ONE(N))){ \
foo(temp, GLUE(variable,NOT_ONE(N))); \
return;
}
Update: Visual Studio version
But I'm on Visual Studio, and I can't make it work. I think the problem is the __VA_ARGS__ expansion works differently on Visual Studio
For VS, I've found another level of indirection of a particular sort (one that separates the macro from its arguments so the arg list can evaluate in a simple (...)
context before it's applied) helps it figure out that commas delimit arguments. Typically I would repeat the same pattern in multiple macros to avoid blue paint.
Here, that translates to the slightly uglier:
#define GLUE(A,B) GLUE_C(GLUE_I,(A,B))
#define GLUE_I(A,B) A##B
#define GLUE_C(A,B) A B
#define SECOND(...) SECOND_C(SECOND_I,(__VA_ARGS__,,))
#define SECOND_I(_,X,...) X
#define SECOND_C(A,B) A B
Upvotes: 2