11

在我的程序中,我想使用显示错误消息的断言。除了众所周知的 C 和 C++ 解决方法之外,还有 BOOST 提供的“真正”解决方案BOOST_ASSERT_MSG( expr, msg )(另请参见带有 message 的 assert()

但是静态消息对我来说还不够,我有时还想显示失败的变量,例如在类似的情况下

BOOST_ASSERT_MSG( length >= 0, "No positive length found! It is " << length )

如您所见,我想将消息“字符串”格式化为stringstreamor ostream,这样我就可以轻松地显示自定义类型(假设我已经定义了相关的格式化函数)。

这里的问题是BOOST_ASSERT_MSG默认情况下需要 achar const *所以不兼容。

assertion_failed_msg()有没有办法以使用流作为消息的方式重新定义/重载?如何?
(我的天真的方法失败了,因为编译器首先想对operator<<("foo",bar)消息本身做一个......)

4

5 回答 5

6

您可以定义自己的宏

#define ASSERT_WITH_MSG(cond, msg) do \
{ if (!(cond)) { std::ostringstream str; str << msg; std::cerr << str.str(); std::abort(); } \
} while(0)
于 2012-08-12T13:06:57.637 回答
6

实现这一点相对微不足道。

BOOST_ASSERT_MSG( length >= 0, (std::stringstream() << "No positive length found! It is " << length).str().c_str() )
于 2012-08-12T13:09:28.620 回答
1

我在它周围使用了BOOST_ASSERT_MSG我自己的包装器,因此用多个指定断言消息operator<<似乎不那么复杂。

#if defined ASSERT_ENABLED 

    #define ASSERT(cond, msg) {\
        if(!(cond))\
        {\
            std::stringstream str;\
            str << msg;\
            BOOST_ASSERT_MSG(cond, str.str().c_str());\
        }\
    }
#else
    #define ASSERT(...) 
#endif

使用示例,提供自定义消息,就像您输出到cout

  ASSERT(execSize == (_oldSize - remaining), "execSize : " << execSize << ", _oldSize : " << _oldSize << ", remaining : " << remaining);

它的作用是,如果ASSERT_ENABLED已定义,则启用断言消息。if(!(cond))部分是优化,它避免了宏参数指定的昂贵的字符串操作msg,如果condtrue

于 2016-02-20T14:00:28.400 回答
1

这是一个不依赖宏的解决方案。相反,它使用了一点点模板和 lambda 语法。

template<typename Fn> 
void assert_fn( bool expr, Fn fn) {
  if (!expr) {
    fn();
    abort();
  }
}

参数fn可以是任何可调用的。
例如,您可以这样称呼它:

assert_fn( a==b, [&](){ cout << "Assertion failed: a="<< a << 
                                " is different from but b=" << b << endl; } ); 

优点是输出是您没有显式调用 abort 并且输出是完全可定制的。当然,这个优势是 lambda 函数样板的七个额外字符[&](){}:)

于 2019-03-27T23:35:34.517 回答
0

如果您仅在 Windows 上工作,则可以查看assert宏。在它使用的引擎盖下_wassert。您可以使用它编写自己的断言宏。例如,在我的情况下,如果我得到一些观点,我想在没有条件的情况下显示断言:

#ifdef DEBUG
    const std::wstring assert_msg = /* build the string here */;
    _wassert(assert_msg.c_str(), _CRT_WIDE(__FILE__), (unsigned)(__LINE__));
#endif

我认为在其他操作系统上你可以做同样的伎俩,看看assert宏。

于 2020-05-01T06:22:54.870 回答