c++预处理器条件参数

C++ preprocessor conditional parameter

本文关键字:参数 条件 处理器 预处理 c++      更新时间:2023-10-16

请注意c++ 03!任何c++ 11的解决方案都不适合我,但是为了知识的缘故,请把它们贴出来。

我知道预处理器可以做这样的事情:
#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

正如您所发现的,您无法用您尝试过的方式做到这一点。宏展开没有内联条件求值,因此必须创建多个宏。

然而,如果你只是试图"优化"正常的代码流,你可以依靠你的编译器的优化。想想看:

if (true) {
   std::cout << "Hin";
}

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

同样:

if (false) {
   std::cout << "Hin";
}

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

同样:

if (4 != 4) {
   std::cout << "Hin";
}

程序仍然不包含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调用宏时,在发布版本中展开为静态已知永远不会匹配的条件。

这个想法是让编译器做优化

您还需要考虑使用一点宏展开技巧来避免后续else子句的问题。

如果条件参数的值域是已知的(最好是较小的),则可以使用预处理器执行此操作。例如,假设参数只能具有值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 << "hin"; )

如果您可以使用Boost,那么您可以使用Boost来完成此操作。预处理:

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

这里的一些答案比其他的更好。我接受的那个是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