C++ 中富有表现力的断言失败消息

Expressive assertion failure messages in C++

单元测试框架通常会提供非常好的断言失败消息(我使用的是 gtest)来描述特定测试的预期值和实际值。此外,您知道函数调用的来源,因为您正在测试 class.

的接口

相比之下,assert 在实施中用作健全性检查时会提供一些但更隐蔽的信息。比如我现在在做的那个。 .

Assertion failed: (latency > std::chrono::milliseconds(0)), function setLatency, file /path/to/my.cpp line 71

所以我知道哪个断言失败了,但我不知道导致它失败的值是什么,更重要的是,我不知道调用 setLatency 的有问题的函数。

一个简单的解决方案通常会交给调试器,但在这种情况下我不能这样做。是否有可能从 class 的实现中获得更具描述性的断言消息?我怎样才能做到这一点?如有必要,我不介意使用第三方库。

我不确定这是否是您要查找的内容,但您可以通过执行以下操作将您喜欢的任何消息附加到 "Assertion failed:.." 消息中:

assert(1==1 && "This is always true");
assert(1==0 && "This always fails");

当然您可以修改字符串以包含值或更多信息。

此问题的常见解决方案是创建断言宏。有关示例,请参见 this question。该答案中宏的最终形式如下:

#define dbgassert(EX,...) \
  (void)((EX) || (realdbgassert (#EX, __FILE__, __LINE__, ## __VA_ARGS__),0))

在您的情况下,realdbgassert 将是一个将任何相关信息打印到 stderr 或其他输出控制台的函数,然后调用 assert 函数本身。根据您需要的信息量,您还可以执行 stack dump,或记录有助于您识别问题的任何其他相关信息。但是,它可以像传递 printf 式格式字符串和相关参数值一样简单。

请注意,如果您的编译器不支持可变参数宏,您可以创建采用特定数量参数的宏。这稍微麻烦一些,但如果您的编译器缺乏支持,则可以选择,例如:

#define dbgassert0(EX) \ ...
#define dbgassert1(EX,p0) \ ...
#define dbgassert2(EX,p0,p1) \ ...