Frage
Ich bin gerade auf ein Projekt mit einer ziemlich großen Code-Basis.
Ich bin meistens mit C ++ zu tun und eine Menge von dem Code, den sie verwendet für ihre Boolesche Logik doppelte Negation schreiben.
if (!!variable && (!!api.lookup("some-string"))) {
do_some_stuff();
}
weiß, dass ich diese Jungs intelligente Programmierer sind, ist es offensichtlich, dass sie tun dies nicht durch Zufall.
Ich bin keine erfahrenen C ++ Experten, meine einzige Vermutung, warum sie dies tun, ist, dass sie absolut positiv machen wollen, dass der Wert die tatsächliche Darstellung boolean ausgewertet. So sie verneinen es, negiert dann, dass es wieder zu bekommen zurück zu seinem eigentlichen Booleschen Wert.
Ist das eine richtige, oder bin ich etwas fehlt?
Lösung
Es ist ein Trick, um bool zu konvertieren.
Andere Tipps
Es ist eigentlich ein sehr nützliches Idiom in manchen Kontexten. Nehmen Sie diese Makros (zB aus dem Linux-Kernel). Für GCC, sind sie wie folgt umgesetzt:
#define likely(cond) (__builtin_expect(!!(cond), 1))
#define unlikely(cond) (__builtin_expect(!!(cond), 0))
Warum tun sie dies tun? GCC __builtin_expect
behandelt seine Parameter als long
und nicht bool
, so braucht es eine gewisse Form der Umwandlung zu sein. Da sie nicht wissen, was cond
, wenn sie diese Makros schreiben, es ist allgemeinste einfach das !!
Idiom zu verwenden.
Sie könnten wahrscheinlich das Gleiche tun gegen 0 durch einen Vergleich, aber meiner Meinung nach, ist es eigentlich einfacher die doppelte Negation zu tun, denn das ist in der Nähe von einem Guss-to-Bool, die C hat.
Dieser Code kann auch in C ++ verwendet werden ... Es ist ein kleinsten gemeinsamen Nenner Sache. Wenn möglich, was sowohl in C und C ++ funktioniert.
Die Programmierer denken, dass es die Operanden konvertieren in bool, sondern weil die Operanden von && bereits implizit konvertiert zu Bool, es ist völlig überflüssig.
Ja, es ist richtig und nicht Sie fehlen nicht etwas. !!
ist eine Konvertierung in bool. Siehe diese Frage für weitere Diskussion.
Es ist eine Technik zu vermeiden, Schreiben (Variable = 0!) - das heißt von konvertieren welcher Art auch immer es zu einem bool ist
.IMO-Code wie dies hat keinen Platz in Systemen, die gewartet werden müssen - weil es nicht sofort lesbarer Code ist (daher die Frage an erster Stelle).
-Code muß lesbar sein - sonst hat man eine Zeit Schuld Vermächtnis für die Zukunft lassen - wie es an der Zeit, etwas zu verstehen, nimmt die unnötig verworren ist
.Es Seitenschritte eine Compiler-Warnung. Versuchen Sie folgendes:
int _tmain(int argc, _TCHAR* argv[])
{
int foo = 5;
bool bar = foo;
bool baz = !!foo;
return 0;
}
Die 'Bar' Linie erzeugt eine "Wert zwingt Bool 'true' oder 'false' (Warnung von Leistung)" auf MSVC ++, aber die 'baz' Linie schleicht durch Ordnung.
Ist Operator! überlastet?
Wenn nicht, tun sie dies wahrscheinlich die Variable auf einen bool zu konvertieren, ohne eine Warnung zu erzeugen. Dies ist auf keinen Fall ein Standard-Weg, Dinge zu tun.
Legacy-C-Entwickler hatten keinen Booleschen Typen, so dass sie oft #define TRUE 1
und #define FALSE 0
und dann verwenden beliebige numerische Datentypen für Boolesche Vergleiche. Nun, da wir bool
haben, werden viele Compiler Warnungen ausgeben, wenn bestimmte Arten von Zuweisungen und Vergleiche sind eine Mischung aus numerischen Typen und Boolesche Typen verwenden. Diese beiden Nutzungen werden schließlich kollidieren, wenn sie mit Legacy-Code zu arbeiten.
Um dieses Problem zu umgehen, einige Entwickler verwenden Sie die folgende Boolesche Identität: !num_value
kehrt bool true
wenn num_value == 0
; false
anders. !!num_value
kehrt bool false
wenn num_value == 0
; true
anders. Die einzige Negation ist ausreichend num_value
zu bool
zu konvertieren; jedoch ist die doppelte Negation notwendig, den ursprünglichen Sinn des Booleschen Ausdruck wiederherzustellen.
Dieses Muster ist bekannt als Idiom , das heißt, etwas häufig von Menschen mit der Sprache verwendet. Deshalb sehe ich es nicht als anti-Muster, so viel wie ich static_cast<bool>(num_value)
würde. Die Besetzung geben könnte sehr gut die richtigen Ergebnisse, aber einige Compiler dann eine Warnung von Leistung abstrahlen, so dass Sie immer noch, dass ansprechen müssen.
Der andere Weg, um diese Adresse zu sagen, (num_value != FALSE)
. Ich bin mit, dass auch in Ordnung, aber alles in allem, !!num_value
ist weit weniger ausführlich, kann klarer und verwirrend ist nicht das zweite Mal, wenn Sie es sehen.
Wie Marcin erwähnt, könnte es auch egal, ob Betreiber Überlastung in ist abspielen. Andernfalls wird in C / C ++ nicht außer egal, ob Sie eine der folgenden Dinge tun:
-
direkter Vergleich zu
true
(oder in C so etwas wie einTRUE
Makro), das fast immer eine schlechte Idee ist. Zum Beispiel:if (api.lookup("some-string") == true) {...}
-
Sie einfach etwas auf einen strikten 0/1 Wert umgewandelt werden soll. In C ++ eine Zuordnung zu einem
bool
wird dies implizit tun (für jene Dinge, die implizit konvertierbarbool
sind). In C oder wenn Sie mit einem nicht-Bool Variable zu tun hat, ist dies ein Idiom, das ich je gesehen habe, aber ich ziehe die(some_variable != 0)
Vielfalt selbst.
Ich denke, im Rahmen eines größeren boolean Ausdruck es einfach unübersichtlich Dinge.
Wenn Variable von Objekttyp ist, könnte es eine haben! definiert Betreiber aber keine Besetzung in bool (oder noch schlimmer eine implizite Umwandlung mit unterschiedlichen Semantik in int. Der Aufruf der! Operator zweimal ergibt sich ein Konvertit Bool, die auch in fremden Fällen funktioniert.
!!
wurde mit Original-C ++ fertig zu werden verwendet, die keinem Typ boolean haben (wie auch nicht C).
Beispiel Probleme:
Innerhalb if(condition)
, die condition
muss auf irgendeine Art wie double, int, void*
zu bewerten, etc., aber nicht bool
, da es noch nicht existiert.
Sprich eine Klasse existierte int256
(eine 256-Bit-Integer) und alle ganzzahligen Wandlungen / Abgüsse überlastet wurden.
int256 x = foo();
if (x) ...
Um zu testen, ob x
„true“ war oder nicht Null ist, if (x)
x
bis zu einem gewissen ganzen Zahl umwandeln würde und und beurteilen, ob das int
nicht Null war. Eine typische Überlastung von (int) x
zurückkehren würde nur die LSbits von x
. if (x)
wurde dann testet nur die LSbits von x
.
Aber C ++ hat den !
Operator. Ein überladenes !x
würde alle Bits von x
typischerweise bewerten. Also, um wieder zu der nicht invertierten Logik if (!!x)
verwendet wird.
Vielleicht sind die Programmierer waren so etwas wie dieses Denken ...
!! myAnswer ist boolean. Im Zusammenhang soll es werden boolean, aber ich liebe es einfach Knall Dinge zu schlagen, um sicher zu machen, denn es ist einmal dort ein mysteriöser Fehler war, die mich gebissen, und bang bang, ich tötete es.
Dies kann ein Beispiel für die double-Bang-Trick finden Sie unter sein das sichere Bool Idiom für weitere Details. Hier fasse ich die erste Seite des Artikels.
In C ++ gibt es eine Reihe von Möglichkeiten, Boolesche Tests für Klassen zur Verfügung zu stellen.
Eine offensichtliche Art und Weise ist
operator bool
Umwandlungsoperator.
// operator bool version
class Testable {
bool ok_;
public:
explicit Testable(bool b=true):ok_(b) {}
operator bool() const { // use bool conversion operator
return ok_;
}
};
Wir können die Klasse testen,
Testable test;
if (test)
std::cout << "Yes, test is working!\n";
else
std::cout << "No, test is not working!\n";
Allerdings ist opereator bool
als unsicher, weil es unsinnig Operationen wie test << 1;
oder int i=test
ermöglicht.
Using
operator!
ist sicherer, weil wir implizite Konvertierung oder Überlastung Probleme zu vermeiden.
Die Implementierung ist trivial,
bool operator!() const { // use operator!
return !ok_;
}
Die beiden idiomatischen Möglichkeiten Testable
Objekt zu testen sind
Testable test;
if (!!test)
std::cout << "Yes, test is working!\n";
if (!test2) {
std::cout << "No, test2 is not working!\n";
Die erste Version if (!!test)
ist, was einige Leute nennen sich die double-Bang-Trick .