2012-08-12 6 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) 

ような場合には、あなたはそれが私が関連を定義したと仮定すると(私は簡単にカスタムタイプを表示できるようにするだろうと私はstringstreamまたはostreamとしてメッセージ「文字列」をフォーマットしたいのですが見ることができるようにフォーミング機能)。

ここで問題となるのは、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

なぜ ''(0)、一方であればif(!(cond))部分は、マクロパラメータmsgによって指定された高価な文字列操作を回避する最適化、ですか? – WiSaGaN

+1

http://stackoverflow.com/questions/1067226/c-multi-line-macro-do-while0-vs-scope-block – Greg

+1

'while(0)'を使用する場合は、 ';'を省略してください。 –

5

を定義することができます。複数operator<<でアサートメッセージを指定することはそれほど複雑思えるように私は、その周りに私自身のラッパーでBOOST_ASSERT_MSGを使用

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

私はそのようにしたいと考えましたが、コンパイラは文句を言います: 'error: 'struct std :: basic_ostream 'に 'str''という名前のメンバーがありません – Chris

+3

ああ、そうです。私はストリングストリームのlibがどのように壊れているのか忘れています。 – Puppy

+0

'std :: stringstream :: str()'を使うには 'operator <<()'の戻り値を 'static_cast ()'しなければなりません。それ以外の場合は、存在しない 'std :: ostream :: str()'を呼び出そうとしています。 – Ruslan

1

。あなたはcoutに出力されているよう

#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 

使用例、カスタムメッセージを提供します。それは何

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

を、ASSERT_ENABLEDが定義されている場合、アサーションメッセージを有効にします。 condtrue

+0

'#if defined ASSERT_ENABLED'が本当に必要ですか?私は、assertが無効になっていると、最適化コンパイラを使用している場合、ステートメントはとにかく削除されると思います。私は正しいですか? –

+0

@SohailSi:はい、#if defined ASSERT_ENABLEDは最適化のためのものです。一般に、リリースビルドはアサーションを無効にすることを意図しています。これによりバイナリからコードが削除されます。バイナリの縮小、コードの削減、命令キャッシュの使用効率の向上assertはデバッグに多くの時間を節約しますが。場合によっては、単純なアサーションチェックで3日間のデバッグ時間を節約することができます。 –

+0

ASSERT_ENABLEDがfalseの場合、コンパイラはBOOST_ASSERT_MSG文を自動的に削除する必要があるため、残りのアサートコードを削除する必要があります。したがって、ASSERT_ENABLEDは明示的にチェックする必要はありません。しかし、なぜ私は明示的に言わなければならないのか分からない。どこが間違っていますか? –

関連する問題