Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ preprocessor conditional parameter

Please note C++03! any C++11 solutions are not good for me, but do post them just for knowledge sake.

I know the preprocessor can do things like:

#define FOO 4
#if FOO == 4
    cout<<"hi"<<endl;
#endif

What I need is:

#define BAR(X)\
    #if X == 4\
       cout<<"hi"<<endl;\
    #endif

main.cpp

BAR(4)

I don't see why all the needed information wouldn't be available in preprocessor time.

So, Please tell me how to achieve this kind of behavior.


edit 1: A normal if condition won't work for my case, because I also do things like:

#define BAR(X)\
    #if X == 4\
       int poop;
    #elif
       double poop;
    #endif
like image 940
Gulzar Avatar asked Aug 24 '15 10:08

Gulzar


People also ask

What is conditional preprocessor?

A preprocessor conditional compilation directive causes the preprocessor to conditionally suppress the compilation of portions of source code.

Which is a conditional pre processing macro?

The conditional directives are: #ifdef - If this macro is defined. #ifndef - If this macro is not defined. #if - Test if a compile time condition is true.

What is the use of conditional preprocessor directive in C?

Preprocessor directives are mostly used in defining macros, evaluating conditional statements, source file inclusion, pragma directive, line control, error detection etc.

What is the difference between #ifdef and #ifndef?

Use the #ifdef statement when you want to compile a section only if a specified expression has been defined with #define. Use #ifndef when you want to compile a section only if a specified expression has not been defined.


2 Answers

As you've discovered, you can't do this in the way that you've attempted. Macro expansion simply doesn't have inline conditional evaluation, so you'd have to create multiple macros instead.

However, if you're just trying to "optimise" normal code flow, you can rely on your compiler's optimizations. Consider this:

if (true) {
   std::cout << "Hi\n";
}

The resulting program will not have any conditional checks in it, because true is always truthy.

Similarly:

if (false) {
   std::cout << "Hi\n";
}

The resulting program will not contain any code to produce output, because false is never truthy.

Similarly:

if (4 != 4) {
   std::cout << "Hi\n";
}

The program will still not contain the std::cout code.

In many cases, you may use this fact to keep your code simple and achieve your desired effect:

#define BAR(X) \
   if ((X) == 4) {
      std::cout << "hi" << std::endl;\
   }

The constraint here, of course, is that an if statement must be valid at the place you write BAR(5), or BAR(42) or BAR(999).

This is also flexible in that now you can use a runtime value (like BAR(i)) and, although the conditional can no longer be collapsed at compile-time, in such a case you'd have no reason to expect that anyway.

I take this approach in my logging macro: the macro, when called for LOG_LEVEL_DEBUG, expands to a conditional that is statically known never to match, in release builds.

The idea is to let the compiler do the optimising.

You're also going to want to consider using a little macro expansion trick to avoid problems with subsequent else clauses.

like image 136
Lightness Races in Orbit Avatar answered Sep 25 '22 02:09

Lightness Races in Orbit


You can do this with the preprocessor if the domain of values for the conditional parameter is well-known (and preferably small). For example, supposing the parameter can only have the values 0 and 1:

#define DOIT_0(X)
#define DOIT_1(X) X
#define CONCAT_(X, Y) X ## Y
#define MAYBE(X) CONCAT_(DOIT_, X)

#define BAR(X) MAYBE(X)(  cout<<"hi"<<endl;  )

#define YESNO 0
BAR(YESNO)

Live on coliru.

Beware of unprotected commas in the argument to BAR.

For equality checks, again over a small range:

#define CONCAT3_(X,Y,Z) X ## Y ## Z
#define EQUAL_0_0(X) X
#define EQUAL_1_1(X) X
#define EQUAL_1_1(X) X
#define EQUAL_0_1(X)
#define EQUAL_0_2(X)
#define EQUAL_1_0(X)
#define EQUAL_1_2(X)
#define EQUAL_2_0(X)
#define EQUAL_2_1(X)
#define DO_IF_EQUAL(X, Y) CONCAT3_(EQUAL_, X, Y)

#define BAR(X) DO_IF_EQUAL(X, 2) ( std::cout << "hi\n"; )
like image 31
rici Avatar answered Sep 23 '22 02:09

rici