C++ preprocessor conditional parameter

[亡魂溺海] 提交于 2019-12-10 14:45:53

问题


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

回答1:


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.




回答2:


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"; )



回答3:


If you can use Boost, you could do this with Boost.Preprocessor:

#define BAR(X) BOOST_PP_EXPR_IF(BOOST_PP_EQUAL(X, 4), cout << "hi" << endl;)



回答4:


Some answers here were better than others. The one I accepted was posted by Christian Kiewiet in a comment, but it was the most accurate for my purpose. Here is the expanded version:

useCases.h

enum UseCases{
    useCase1=0,
    useCase2,
    useCaseNumber//always last for iterations
} 

specializer.h

#include "useCases.h"
<template UseCases theCase>
struct StaticCase{
    //empty, thus accidents calling from this can't happen
}

//specialization
template<>
class StaticCase<UseCases::useCase1>{
     typedef int T;
     static foo(T arg){cout<<"case1";};
}


template<>
class StaticCase<UseCases::useCase2>{
     typedef double T;
     static foo(){cout<<"case2";};
}

Now, I can do

#define BAR1(useCase) StaticCase<useCase>::foo(); 

or

#define BAR2(useCase) StaticCase<useCase>::T var;

and the call:

BAR1(UseCases::useCase1)//output - case1
BAR1(UseCases::useCase2)//output - case2


来源:https://stackoverflow.com/questions/32179717/c-preprocessor-conditional-parameter

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!