C ++:忽略声明

时间:2017-12-28 14:20:19

标签: c++ macros c-preprocessor

我正在使用C ++预处理器宏来选择性地忽略一些代码块以用于测试目的,例如

#ifdef __SAFE
    #define note 
    #define ensure(X) if(X) {} else 
#else
    #define note while(false)
    #define ensure(X) while(false)
#endif

直观地,note执行一些代码(通常设置一些保护变量),ensure执行下一个代码块(如果违反了条件)。有了这些宏,我可以写:

note { var = true }
ensure(var == true) { throw new std::exception; }

并且代码将编译是否定义了__SAFE(并且编译器很可能会删除丢失的代码)。这很好,因为它的行为基本上是C ++语言的扩展。

我还想在__SAFE未定义的情况下同样跳过类中的一些数据成员声明。上面的技巧不再起作用,因为在类声明中不允许流控制。我想声明一些宏guard,其类为:

class A {
guard int x;
}

仅在定义int x时才包含成员__SAFE

可能的解决方案:

  • 一些预编译器技巧可以用guard替换//,从而获得所需的结果;但它们只能在某些编译器中工作(特别是在g++中)。此外,似乎在预处理之前删除了注释,因此它可能无论如何都不会工作。
  • 使用#ifdef ... #endif块围绕声明。它有效,但有些冗长。
  • 如果guard(X)已定义,则X定义为__SAFE,否则定义为空格。这也有效,但是摆脱括号会很好,只需将参数作为"所有内容直到下一个分号"。

我知道C ++预处理器不是很强大。我想知道是否有一个美学上令人愉快的解决方案;否则我只会使用后一种选择。

1 个答案:

答案 0 :(得分:3)

从C ++ 11开始,您可以使用模板别名,例如:

struct A {
  guarded<int> x;
};

其中guarded定义为:

#ifdef YOUR_SAFE_MACRO

template<typename T>
using guarded_impl = T;

#define guarded guarded_impl

#else

template<typename T>
struct guarded_impl {};

#define guarded static guarded_impl

#endif

如果变量在YOUR_SAFE_MACRO关闭时使用ODR,则还会产生链接器错误(如果打开,虚拟静态变量仍然存在,但如果未使用则应在链接时进行优化) )。

你可以在&lt; C ++ 11也是如此,但它会稍微冗长。

那就是说,我猜 note 确保 guard 是太常见的名称,不能用作宏,但仍希望没有名字冲突发生了,所以我强烈反对这样的事情(你已被警告:))

此外,阅读代码的人会因为static隐藏在一个看起来像模板的宏中而感到困惑......在我看来,good'ol #ifdef会更好。