Ich konnte die Antwort selbst nicht kommentieren, also: über Verwenden von Komma, um die Notwendigkeit eines Klammerpaars zu verhindern
%Vor%Hier gibt debugbreak () void zurück, aber wir wollen immer noch 0 als rvalue haben.
Wie funktioniert (debugbreak (), 0), um 0 zurückzugeben? Ich verstehe, dass der Rückgabewert von debugbreak () verworfen wird und 0 zurückgegeben wird, aber Debugbreak generiert eine Ausnahme, also wie kann alles danach ausgewertet werden? Ich nehme an, dass meine Frage auf jeden ähnlichen binären Operator verallgemeinert werden kann, wo der erste Teil, der ausgewertet wird, das Programm verlässt.
Nichts wird ausgewertet, wenn das assert ausgelöst wird, aber beide Ausdrücke müssen den richtigen Rückgabetyp haben, sonst bricht dieses Makro nur die Kompilierung ab.
Es ist ein Typsystem-Hack.
%Vor% Der Operator ||
benötigt zwei bool
-typisierte (oder konvertierbare) Ausdrücke. debugbreak()
ist void
-typed. Verwenden Sie die folgende Regel, um bool
zu erstellen:
Dies ist das gleiche wie {FOO; BAR}
, außer dass ein Block (in geschweiften Klammern) keinen Typ hat.
Die Grundidee ist ziemlich einfach. Er versucht, einen Effekt zu erzielen, der fast so ist, als hätte er geschrieben: if (!expr) debugbreak();
. Für ein Makro will er das als einzigen Ausdruck. Dafür benutzt er ||
, was sein linkes Argument auswertet, dann, wenn und nur wenn das falsch ist, wertet er das rechte Argument aus - dann wird ein Gesamtergebnis erzeugt, das das logische ODER der beiden Operanden ist.
In diesem Fall kümmert er sich nicht wirklich um das logische OR, das als Ergebnis erzeugt wird; er will nur die linke auswerten, dann wenn es falsch ist, die rechte auswerten. Der Compiler ist jedoch nicht - er fordert insbesondere, dass beide Operanden von ||
einen Typ haben, der in bool (oder in C, 0 oder 1) konvertiert werden kann.
Um dem Compiler das zu geben, benutzt er den Kommaoperator, der seinen linken Operanden berechnet, dann seinen rechten Operanden und erzeugt als Ergebnis den Wert des rechten Operanden. Dadurch kann er debugbreak()
auswerten, während 0
den Compiler zufriedenstellt, indem er ihm einen int als Ergebniswert gibt, der dann ODER mit einem beliebigen Wert von expr
erzeugt werden kann, um das Ergebnis des Gesamtausdruck (der natürlich irrelevant ist und fast sicher ignoriert wird).
Ich denke, was Ihr alles vermisst, ist die Tatsache, dass (A || B) den Regeln des Kurzschlusses folgt.
Wenn A wahr ist, dann gibt es KEINE Notwendigkeit, B zu bewerten. Da B nicht ausgewertet werden muss, wird DebugBreak () niemals aufgerufen.
Wenn A falsch ist, müssen wir B auswerten, um die Ausgabe von (A || B) zu bestimmen. Es gibt keinen Kurzschluss. (DebugBreak (), 0) von passender (DebugBreak (), false)
Tags und Links c++