C++ 预处理器条件参数

C++ preprocessor conditional parameter

请注意C++03!任何 C++11 解决方案都不适合我,但 post 只是为了知识的缘故。

我知道预处理器可以做这样的事情:

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

我需要的是:

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

main.cpp

BAR(4)

我不明白为什么所有需要的信息在预处理器时间内都不可用。

所以,请告诉我如何实现这种行为。


编辑 1: 正常的 if 条件不适用于我的情况,因为我也做类似的事情:

#define BAR(X)\
    #if X == 4\
       int poop;
    #elif
       double poop;
    #endif

如您所见,您无法按照您尝试过的方式进行操作。宏扩展根本没有内联条件评估,因此您必须创建多个宏。

但是,如果您只是想 "optimise" 正常的代码流,您可以依赖编译器的优化。考虑一下:

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

生成的程序不会有任何条件检查,因为 true 总是真实的。

同样:

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

生成的程序将不包含任何生成输出的代码,因为 false 永远不会为真。

同样:

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

程序仍不包含 std::cout 代码。

在很多情况下,您可以利用这个事实来保持代码简单并达到您想要的效果:

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

这里的约束当然是if语句必须在你写BAR(5)BAR(42)BAR(999)的地方有效。

这也很灵活,因为现在您可以使用运行时值(如 BAR(i)),并且尽管条件不能再在编译时折叠,但在这种情况下您没有无论如何都有理由期待这一点。

我在我的日志记录宏中采用了这种方法:在为 LOG_LEVEL_DEBUG 调用时,该宏在发布版本中扩展为静态已知永远不会匹配的条件。

想法是让编译器进行优化

您还需要考虑使用 a little macro expansion trick to avoid problems with subsequent else clauses

如果你可以使用 Boost,你可以用 Boost.Preprocessor:

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

如果条件参数的值域是众所周知的(最好是小的),您可以使用预处理器执行此操作。例如,假设参数可以 only 具有值 0 和 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.

注意 BAR.

参数中未受保护的逗号

对于相等性检查,同样是在一个小范围内:

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

这里的一些答案比其他答案好。 我接受的那个是 Christian Kiewiet 在评论中发布的,但它对我的目的来说是最准确的。 这是扩展版本:

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

现在,我可以做到

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

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

和调用:

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