大多数答案建议static_cast<void>(expression)
在构建中使用技巧Release
来抑制警告,但如果您的意图是真正进行检查,这实际上是次优的Debug
。相关断言宏的目标是:
Debug
在模式下执行检查
Release
在模式下什么都不做
- 在所有情况下都不发出警告
问题是void-cast方法无法达到第二个目标。虽然没有警告,但您传递给断言宏的表达式仍将被评估。例如,如果您只是进行变量检查,那可能没什么大不了的。但是如果你在你的断言检查中调用一些函数ASSERT(fetchSomeData() == data);
(这在我的经验中很常见)怎么办?该fetchSomeData()
函数仍将被调用。它可能快速而简单,也可能不是。
您真正需要的不仅是警告抑制,而且可能更重要的是 -不评估仅调试检查表达式。这可以通过我从专门的Assert库中获取的一个简单技巧来实现:
void myAssertion(bool checkSuccessful)
{
if (!checkSuccessful)
{
// debug break, log or what not
}
}
#define DONT_EVALUATE(expression) \
{ \
true ? static_cast<void>(0) : static_cast<void>((expression)); \
}
#ifdef DEBUG
# define ASSERT(expression) myAssertion((expression))
#else
# define ASSERT(expression) DONT_EVALUATE((expression))
#endif // DEBUG
int main()
{
int a = 0;
ASSERT(a == 1);
ASSERT(performAHeavyVerification());
return 0;
}
所有的魔法都在DONT_EVALUATE
宏中。很明显,至少从逻辑上讲,在它内部永远不需要对表达式的求值。为了加强这一点,C++ 标准保证只评估条件运算符的一个分支。这是报价:
5.16 条件运算符 [expr.cond]
逻辑或表达式?表达式:赋值表达式
条件表达式从右到左分组。第一个表达式根据上下文转换为布尔值。它被评估,如果为真,则条件表达式的结果是第二个表达式的值,否则是第三个表达式的值。仅评估这些表达式之一。
我已经在 GCC 4.9.0、clang 3.8.0、VS2013 Update 4、VS2015 Update 4 中测试了这种方法,警告级别最苛刻。在所有情况下都没有警告,并且检查表达式永远不会在Release
构建中评估(实际上整个事情已经完全优化了)。请记住,使用这种方法,如果将具有副作用的表达式放在断言宏中,您将很快遇到麻烦,尽管这首先是一种非常糟糕的做法。
此外,我希望静态分析器可能会使用这种方法警告“表达式的结果始终是恒定的”(或类似的东西)。我已经使用 clang、VS2013、VS2015 静态分析工具对此进行了测试,并且没有收到此类警告。