2012-08-12 88 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