我正在使用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 ++预处理器不是很强大。我想知道是否有一个美学上令人愉快的解决方案;否则我只会使用后一种选择。
答案 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
会更好。