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?

War es hilfreich?

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 ein TRUE 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 konvertierbar bool 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.

Ref

Es ist richtig, aber in C, sinnlos hier -. ‚Wenn‘ und ‚&&‘ die gleiche Art und Weise dem Ausdruck ohne behandeln würde ‚!!‘

Der Grund, dies in C ++ zu tun, nehme ich an, dass ‚&&‘ überlastet werden könnte. Aber dann, so konnte ‚!‘, So dass es nicht wirklich garantieren Sie einen Bool erhalten, ohne für die Arten von variable und api.call Blick auf den Code. Vielleicht hat jemand mit mehr C ++ Erfahrung könnte erklären; Vielleicht ist es als Abwehr-in-Tiefe Art von Maßnahme gemeint, keine Garantie.

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.

  

Usingoperator! 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 .

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top