#define M(N)\
#if N == 5\
/*several lines of code that
Can't be replaced with a
tertnary operator*/
#else\
N;\
#endif
When I use this macro like so
M(5);
I expect the output to be
// everything within the #if #else block
But it doesn't compile.
I'm not surprised that it doesn't compile: I know #if cannot be used on a continuation line ie "\".
I've also tried
#define POUND_IF #if
And then to use POUND_IF but doesn't work.
Is this possible to do?
Is there some nifty Boost pre-processor stuff that can be used?
Succinctly, you can't. You can rely on the optimizer instead, though:
#define M(N)\
do { if (N == 5) { \
/*several lines of code that
Can't be replaced with a
ternary operator*/ \
} else { N; } } while (0)
If the compiler can determine that the value of N
will be 5 when the code is run (e.g. you write M(5)
), then only the code in the body of the if
will be included in the generated code. If the compiler can determine that the value of N
will not be 5 when the code is run, it will generate only the code in the body of the else
clause. And if it can't determine what the value will be, the preprocessor would not have been able to do so either, but the compiler will include all the code.
A macro definition cannot include preprocessor directives (anything beginning with a #
).
To conditionally expand to certain values requires rather involved macrology and might not always work out the way you want. The example above could be written something like this:
#define ONE_OR_TWO(...) ONE_OR_TWO_(__VA_ARGS__, 2, 1,)
#define ONE_OR_TWO_(_1, _2, X, ...) X
#define CAT(A, B) CAT_(A, B)
#define CAT_(A, B) A ## B
#define M(N) CAT(IF_, ONE_OR_TWO(CAT(IS_, N)))({\
code; \
code; \
}, N)
#define IS_5 ,
#define IF_1(A, B) B
#define IF_2(A, B) A
M(5); //-> { code; code; }
M(8); //-> 8
This is incredibly fragile though. You can only use certain types of expression as the argument to M
, for instance - they have to have a syntactic structure that allows for concatenation, and no unwrapped commas - and it only works for predetermined values (e.g. to compare against something more complicated than a simple number is not possible with this method, because you can't build a macro name out of a more complex expression).
But in principle, it can be done. You just need thousands upon thousands of lines of macro definitions to cover a useful set of cases beyond the trivial ones like this. You can get those by using a metaprogramming library like Order-PP or Boost.Preprocessor, but be prepared for obscure error messages if you slip up in the syntax even slightly.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With