2012-08-12 14 views
9

In meinem Programm möchte ich Behauptungen verwenden, die eine Fehlermeldung anzeigen. Neben den bekannten Abhilfen für C und C++ gibt es die „echte“ Lösung als BOOST bietet BOOST_ASSERT_MSG(expr, msg) (siehe auch assert() with message)Mit dynamischer Nachricht bestätigen?

Aber eine statische Meldung ist nicht genug für mich, ich will auch mal zeigen, die ausgefallenen Variablen, z.B in einem Fall wie

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

Wie Sie sehen, ich möchte die Meldung „String“ zu formatieren als stringstream oder ostream wie das erlauben würde mir benutzerdefinierte Typen zeigen leicht an (vorausgesetzt, dass ich die relevant definiert haben Formatierungsfunktion).

Das Problem hierbei ist, dass BOOST_ASSERT_MSG ist standardmäßig ein char const * erfordert das ist so nicht kompatibel.

Gibt es eine Möglichkeit, assertion_failed_msg() auf eine solche Weise neu zu definieren/zu überlasten, dass die Verwendung eines Streams als Nachricht funktioniert? Wie?
(Mein naiver Ansatz gescheitert wie der Compiler zunächst ein operator<<("foo",bar) auf der Nachricht selbst tun ... wollte)

Antwort

6

Sie könnten definieren Sie Ihre eigene Makro

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

ist Warum 'while (0)'? – WiSaGaN

+1

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

+1

Wenn Sie 'while (0)' verwenden, lassen Sie das ';' weg. –

5

Es ist relativ trivial, dies zu erreichen.

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

Ich hoffte, es so zu machen, aber der Compiler beschwert sich: 'Fehler: 'struct std :: basic_ostream ' hat kein Mitglied namens 'str'' – Chris

+3

Oh, yeah. Ich vergesse immer wieder wie kaputt die stringstream lib ist. – Puppy

+0

Sie müssen 'static_cast Ruslan

1

verwende ich die BOOST_ASSERT_MSG mit meinem eigenen Wrapper um ihn herum, so dass die Assertion-Nachricht mit mehrere Angabe scheint operator<< weniger komplex.

#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 

Verwendungsbeispiel, benutzerdefinierte Nachricht liefern wie Sie cout ausgeben:

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

Was sie tut, ist, wenn ASSERT_ENABLED definiert ist, die Behauptung Nachrichten ermöglichen. if(!(cond)) Teil ist die Optimierung, die die kostspieligen Zeichenkettenoperationen vermeidet, die durch den Makroparameter msg spezifiziert werden, wenn condtrue

+0

Brauchen Sie wirklich '#if defined ASSERT_ENABLED'? Ich denke, wenn assert deaktiviert ist, werden die Anweisungen sowieso entfernt, wenn ein optimierender Compiler verwendet wird. Hab ich recht? –

+0

@SohailSi: Ja, '#if definiert ASSERT_ENABLED' ist für die Optimierung. Im Allgemeinen sind Release-Builds mit deaktivierten Assertions gemeint. Dies entfernt Code aus der Binärdatei. Kleinere Binärdatei, weniger Code, bessere Verwendung des Befehlscache. Während Assert beim Debugging viel Zeit spart. Manchmal kann eine einfache Bestätigungsprüfung 3 Tage Debugging-Zeit sparen. –

+0

Ich meine, wenn definiert ASSERT_ENABLED ist falsch, dann sollte der Compiler automatisch die BOOST_ASSERT_MSG-Anweisungen entfernen, daher sollte der Rest Ihres Assert-Code entfernen. ASSERT_ENABLED muss also nicht explizit überprüft werden. Aber ich bin mir nicht sicher, warum das explizit gesagt werden muss.Wo liege ich falsch? –

Verwandte Themen