我正在使用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++前处理器不是很强大。我只想知道是否有一种美学上令人满意的解决方案;否则,我将仅使用后一种选项。

    最佳答案

    从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变量,则还具有给出链接器错误的好处(如果打开,则伪静态变量仍然存在,但是如果未使用,则应在链接时进行优化)。

    您也可以在
    就是说,我想请注意,请确保确保和保护是太普通的名称,不能用作宏,并且仍然希望不会发生名称冲突,因此,我强烈建议您不要使用这种方法(已警告您:))

    而且,人们在阅读您的代码时会因为将static隐藏在看起来像模板的宏中而感到困惑……在我看来,好的#ifdef将是更好的解决方案。

    关于c++ - C++:忽略声明,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/48009145/

    10-11 22:44
    查看更多