2012-08-12 83 views
9

在我的程序中,我想使用显示错误消息的断言。除了C和C众所周知的解决办法++有“真实”的解决方案,BOOST提供BOOST_ASSERT_MSG(expr, msg)(也assert() with message见)断言与动态消息?

但是静态信息是不够的,我也想有时显示失败的变量,例如像

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

的情况下,你可以看到,我想格式化消息“字符串”作为stringstreamostream为会允许我轻松地显示自定义类型(假设我已经定义了相关的格式化功能)。

这里的问题是,BOOST_ASSERT_MSG默认需要char const *,因此不兼容。

有没有办法重新定义/重载assertion_failed_msg()这样一种方式,使用流作为消息将工作?怎么样?
(我幼稚的做法失败,因为编译器首先想做消息本身的operator<<("foo",bar) ...)

回答

6

你可以定义自己的宏

#define ASSERT_WITH_MSG(cond, msg) do \ 
{ if (!(cond)) { std::ostringstream str; str << msg; std::cerr << str.str(); std::abort(); } \ 
} while(0) 
+0

为什么'while(0)'?是最优化的,它避免了宏参数msg指定的代价昂贵的字符串操作。 – WiSaGaN 2012-08-12 13:08:39

+1

请参阅http://stackoverflow.com/questions/1067226/c-multi-line-macro-do-while0-vs-scope-block – Greg 2012-08-12 13:10:04

+1

如果使用'while(0)',则省略';'。 – 2012-08-12 13:42:00

5

这是比较琐碎实现这一目标。

BOOST_ASSERT_MSG(length >= 0, (std::stringstream() << "No positive length found! It is " << length).str().c_str()) 
+4

我希望这样做,但编译器抱怨:'错误:'struct std :: basic_ostream '没有名为'str''的成员 – Chris 2012-08-12 14:13:08

+3

哦,是的。我一直在忘记stringstream lib是如何损坏的。 – Puppy 2012-08-12 14:35:20

+0

你必须'static_cast ()'operator <<()'的返回值才能使用'std :: stringstream :: str()'。否则,你试图调用不存在的'std :: ostream :: str()'。 – Ruslan 2016-04-29 10:48:50

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))如果condtrue

+0

你真的需要'#if定义ASSERT_ENABLED'吗?我认为,如果断言被禁用,则无论如何都会删除语句,如果使用优化编译器。我对么? – 2016-06-21 19:11:53

+0

@SohailSi:是的,'#if defined ASSERT_ENABLED'是为了优化。一般来说,发布版本的意图是禁用断言。这会从二进制代码中删除代码。更小的二进制代码,更少的代码,更好地使用指令缓存。虽然assert节省了大量的时间在调试。有时,简单的断言检查可以节省3天的调试时间。 – 2016-06-23 07:28:16

+0

我的意思是,如果定义的ASSERT_ENABLED为false,那么编译器应该自动删除BOOST_ASSERT_MSG语句,因此应该删除其余的断言代码。所以ASSERT_ENABLED不需要明确检查。但我不确定为什么需要明确说明。我错在哪里? – 2016-06-23 11:02:34