如何使#if #endif 成为宏的一部分

How to make #if #endif part of a macro

#define M(N)\
#if N == 5\
    /*several lines of code that 
      Can't be replaced with a   
      tertnary operator*/
#else\
    N;\
#endif

当我这样使用这个宏时

M(5);

我希望输出是

// everything within the #if #else block

但它无法编译。

我对它无法编译并不感到惊讶:我知道#if 不能用于续行,即“\”。

我也试过了

#define POUND_IF #if

然后使用 POUND_IF 但不起作用。

这可能吗?

是否有一些漂亮的 Boost 预处理器可以使用?

宏定义不能包含预处理器指令(任何以 # 开头的指令)。

有条件地扩展到某些值需要相当复杂的宏观学,并且可能并不总是按照您想要的方式计算。上面的例子可以这样写:

#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

虽然这非常脆弱。您只能使用某些类型的表达式作为 M 的参数,例如 - 它们必须具有允许连接的句法结构,并且没有展开的逗号 - 并且它仅适用于预定值(例如与使用此方法无法获得比简单数字更复杂的东西,因为您无法从更复杂的表达式中构建宏名称)。

但原则上是可以做到的。你只需要成千上万行宏定义来涵盖像这样的琐碎案例之外的一组有用案例。您可以通过使用像 Order-PP or Boost.Preprocessor 这样的元编程库来获得这些信息,但是如果您在语法上稍有失误,请准备好接收模糊的错误消息。

简而言之,你不能。不过,您可以依赖优化器:

#define M(N)\
    do { if (N == 5) { \
    /*several lines of code that 
      Can't be replaced with a   
      ternary operator*/ \
    } else { N; } } while (0)

如果编译器可以判断N的值在代码为运行时为5(比如你写M(5)),那么只有body中的代码if 将包含在生成的代码中。如果编译器可以确定代码为运行时N的值不会是5,那么它将只生成else子句主体中的代码。如果它不能确定值是什么,预处理器也不能这样做,但编译器将包含所有代码。