Właśnie przyszedłem do projektu z dość dużą bazą kodu.
Zajmuję się głównie C ++ i wiele z ich kodu używa podwójnej negacji dla logiki boolowskiej.
if (!!variable && (!!api.lookup("some-string"))) {
do_some_stuff();
}
Wiem, że ci faceci to inteligentni programiści, oczywiste jest, że nie robią tego przez przypadek.
Nie jestem doświadczonym ekspertem od C ++, moje jedyne przypuszczenie, dlaczego to robią, to to, że chcą mieć absolutną pewność, że oceniana wartość jest rzeczywistą reprezentacją boolowską. Więc negują to, a następnie ponownie negują, aby przywrócić mu rzeczywistą wartość logiczną.
Czy to prawda, czy czegoś mi brakuje?
Odpowiedzi:
Konwersja na bool to sztuczka.
źródło
bool
typ, aby uniknąć przechowywania wartości inne niż1
i0
zmiennych logicznych.!!
lub!=0
rozwiązuje problem, a wśród tych dwóch znajduję poprzedni środek czyszczący (ponieważ będzie działał na większej liczbie typów). Zgadzam się również, że w omawianym kodzie nie ma powodu, aby go używać.Właściwie jest to bardzo przydatny idiom w niektórych kontekstach. Weźmy te makra (przykład z jądra Linuksa). W przypadku GCC są one zaimplementowane w następujący sposób:
Dlaczego muszą to robić? GCC
__builtin_expect
traktuje swoje parametry jakolong
a niebool
, więc potrzebna jest jakaś forma konwersji. Ponieważ nie wiedzą, cocond
jest, kiedy piszą te makra, najogólniej jest po prostu użyć!!
idiomu.Prawdopodobnie mogliby zrobić to samo, porównując z 0, ale moim zdaniem łatwiej jest zrobić podwójną negację, ponieważ jest to najbliższe rzutowaniu na bool, które ma C.
Ten kod może być również używany w C ++ ... to rzecz o najniższym wspólnym mianowniku. Jeśli to możliwe, zrób to, co działa zarówno w C, jak i C ++.
źródło
Programiści myślą, że przekonwertuje operand na bool, ale ponieważ operandy && są już niejawnie konwertowane na bool, jest to całkowicie zbędne.
źródło
Jest to technika unikania pisania (zmienna! = 0) - tj. Konwertowania dowolnego typu na bool.
Taki kod IMO nie ma miejsca w systemach, które wymagają konserwacji - ponieważ nie jest to kod czytelny od razu (stąd pytanie na pierwszym miejscu).
Kod musi być czytelny - w przeciwnym razie zostawisz spuściznę długu czasu na przyszłość - ponieważ zrozumienie czegoś, co jest niepotrzebnie zagmatwane, wymaga czasu.
źródło
bool(expr)
: robi to dobrze i wszyscy rozumieją intencje od pierwszego wejrzenia.!!(expr)
jest podwójną negacją, która przypadkowo przekształca się w bool ... to nie jest proste.Tak, jest poprawne i nie, nie brakuje Ci czegoś.
!!
jest konwersją do bool. Zobacz to pytanie, aby uzyskać więcej dyskusji.źródło
Pomija ostrzeżenie kompilatora. Spróbuj tego:
Linia „bar” generuje „wymuszającą wartość bool„ true ”lub„ false ”(ostrzeżenie dotyczące wydajności)” w MSVC ++, ale wiersz „baz” wymyka się dobrze.
źródło
bool
rodzaju - wszystko jest zakodowany jako0
lub1
w sposóbint
.Jest operatorem! przeciążony?
Jeśli nie, prawdopodobnie robią to, aby przekonwertować zmienną na bool bez generowania ostrzeżenia. To zdecydowanie nie jest standardowy sposób robienia rzeczy.
źródło
Deweloperzy Legacy C nie miał typ Boolean, więc często
#define TRUE 1
i#define FALSE 0
, a następnie wykorzystywane dowolne typy danych numerycznych dla logicznych porównań. Teraz, gdy już mamybool
, wiele kompilatorów będzie emitować ostrzeżenia, gdy pewne typy przypisań i porównań zostaną wykonane przy użyciu kombinacji typów liczbowych i logicznych. Te dwa zastosowania ostatecznie zderzą się podczas pracy ze starszym kodem.Aby obejść ten problem, niektórzy programiści używają następującej tożsamości logicznej:
!num_value
zwracabool true
ifnum_value == 0
;false
Inaczej.!!num_value
zwraca,bool false
jeślinum_value == 0
;true
Inaczej. Pojedyncza negacją jest wystarczający do przekształcenianum_value
nabool
; Jednak podwójna negacja jest konieczna, aby przywrócić pierwotny sens wyrażenia boolowskiego.Ten wzorzec jest znany jako idiom , czyli coś powszechnie używanego przez osoby zaznajomione z językiem. Dlatego nie uważam tego za anty-wzór, tak bardzo, jak bym chciał
static_cast<bool>(num_value)
. Rzutowanie może bardzo dobrze dać poprawne wyniki, ale niektóre kompilatory emitują wtedy ostrzeżenie o wydajności, więc nadal musisz się tym zająć.Innym sposobem rozwiązania tego problemu jest powiedzenie
(num_value != FALSE)
. Z tym też!!num_value
nie przeszkadza , ale w sumie jest o wiele mniej rozwlekły, może być wyraźniejszy i nie wprowadza zamieszania, gdy zobaczysz go po raz drugi.źródło
!!
był używany do radzenia sobie z oryginalnym C ++, który nie miał typu boolowskiego (podobnie jak C).Przykładowy problem:
Wewnątrz
if(condition)
, nacondition
potrzeby oceny do pewnego rodzaju podobnegodouble, int, void*
, etc., ale niebool
, ponieważ jeszcze nie istnieje.Załóżmy, że istnieje klasa
int256
(256-bitowa liczba całkowita) i wszystkie konwersje / rzutowania na liczby całkowite zostały przeciążone.Aby sprawdzić, czy
x
było „prawdziwe”, czy niezerowe, należyif (x)
przekonwertowaćx
na jakąś liczbę całkowitą, a następnie ocenić, czy jestint
ona niezerowa. Typowe przeciążenie(int) x
zwróci tylko LSbitówx
.if (x)
testował wtedy tylko LSbityx
.Ale C ++ ma
!
operator. Przeciążony!x
typ zwykle oceniałby wszystkie bityx
. Aby wrócić do logiki nieodwróconej,if (!!x)
jest używana.Ref Czy starsze wersje C ++ używały operatora „int” klasy podczas oceny warunku w instrukcji „if ()”?
źródło
Jak wspomniał Marcin , może mieć znaczenie, jeśli w grę wchodzi przeciążanie operatorów. W przeciwnym razie w C / C ++ nie ma to znaczenia, chyba że wykonujesz jedną z następujących czynności:
bezpośrednie porównanie do
true
(lub w C coś w rodzajuTRUE
makra), co jest prawie zawsze złym pomysłem. Na przykład:if (api.lookup("some-string") == true) {...}
po prostu chcesz, aby coś zostało przekonwertowane na ścisłą wartość 0/1. W C ++ przypisanie do a
bool
zrobi to niejawnie (dla tych rzeczy, które są niejawnie konwertowane nabool
). W C lub jeśli masz do czynienia ze zmienną inną niż bool, jest to idiom, który widziałem, ale sam wolę tę(some_variable != 0)
odmianę.Myślę, że w kontekście większego wyrażenia boolowskiego po prostu zaśmieca to wszystko.
źródło
Jeśli zmienna jest typu obiektowego, może mieć! operator zdefiniowany, ale bez rzutowania na bool (lub, co gorsza, niejawne rzutowanie na int z inną semantyką. Dwukrotne wywołanie operatora! powoduje konwersję na bool, która działa nawet w dziwnych przypadkach.
źródło
Jest poprawne, ale w C, tutaj bez sensu - „if” i „&&” traktowałyby wyrażenie w ten sam sposób bez „!!”.
Przypuszczam, że powodem tego w C ++ jest to, że '&&' może być przeciążony. Ale z drugiej strony może „!”, Więc tak naprawdę nie gwarantuje uzyskania wartości bool bez patrzenia na kod typów
variable
iapi.call
. Może ktoś z większym doświadczeniem w C ++ mógłby to wyjaśnić; być może jest to środek dogłębnej obrony, a nie gwarancja.źródło
if
lub&&
, ale użycie!!
może pomóc w niektórych kompilatorach, jeśliif (!!(number & mask))
zostanie zastąpionebit triggered = !!(number & mask); if (triggered)
; na niektórych wbudowanych kompilatorach z typami bitów przypisanie np. 256 do typu bitowego da zero. Bez!!
pozornie bezpieczna transformacja (skopiowanieif
warunku do zmiennej, a następnie rozgałęzienie) nie będzie bezpieczna.Może programiści myśleli o czymś takim ...
!! myAnswer jest logiczna. W kontekście powinno to stać się logiczne, ale po prostu uwielbiam robić huk, aby się upewnić, ponieważ kiedyś pojawił się tajemniczy błąd, który mnie ugryzł i bang bang, zabiłem go.
źródło
Może to być przykład sztuczki z podwójnym uderzeniem , zobacz The Safe Bool Idiom, aby uzyskać więcej informacji. Tutaj podsumowuję pierwszą stronę artykułu.
W C ++ istnieje wiele sposobów na zapewnienie testów logicznych dla klas.
Możemy przetestować klasę,
Jednak
opereator bool
jest uważany za niebezpieczny, ponieważ zezwala na bezsensowne operacje, takie jaktest << 1;
lubint i=test
.Wdrożenie jest banalne,
Dwa idiomatyczne sposoby testowania
Testable
obiektu toPierwsza wersja
if (!!test)
to coś, co niektórzy nazywają sztuczką z podwójnym hukiem .źródło
explicit operator bool
aby zapobiec niejawnej konwersji do innych typów całkowitych.