2009-08-18 12 views
5

Tym, czego naprawdę chcę, jest operator || =.zachowanie funkcji bool z operatorami nie-boolowskimi

old_value = old_value || possible_new_value; 
old_value ||= possible_new_value; 

Druga linia to błąd kompilatora (C++ nie ma operatora || =).

Więc jakie są moje inne opcje?

old_value += possible_new_value; 
old_value |= possible_new_value; 

Podczas gdy jestem na temat, w jaki sposób Bool zachowuje się z innymi operatorami nie boolean?

- 
-= 
& 
&= 
... 

Mogę to zweryfikować empirycznie, ale najbardziej interesuje mnie to, co mówi standard.

Odpowiedz

12

Według 4,7 (Integral konwersje), pkt 4, „Jeśli typ docelowy jest bool patrz 4.12.Jeśli typem źródłowym jest bool, wartość false jest konwertowana na zero, a wartość true jest konwertowana na jeden. "W 4.12," Wartość rytmu arytmetycznego, wyliczenia, wskaźnika lub wskaźnika na typ pręta może zostać przekonwertowana na rwartość typu bool. Wartość zerowa, zerowa wartość wskaźnika lub wartość wskaźnika elementu zerowego jest przekształcana na false; Inne wartości przekształca się true „.

W sytuacji, gdy bool argumenty nie są dozwolone integralne argumenty, tym bool zostanie przekształcona w integralny typu. Gdy wynik równy jest przechowywany w zmiennej bool, zostanie . być przekształcone bool

Dlatego będzie można używać + i * jako logiczna lub ai, i można użyć | i & również nie można uciec z ich mieszania, jak (bool1 + BOOL2.) & bool3 przyniesie false, jeśli wszystkie trzy zmienne to true. ((1 + 1) & 1 to 2 & 1, czyli 0 lub fałsz.)

Pamiętaj, że | i || nie działają identycznie nawet tutaj. | oceni obie strony, a następnie oceni bitowe lub. || oceni pierwszy operand, wtedy tylko, jeśli był fałszywy, oceni drugi.

Nie będę omawiać tutaj kwestii stylistycznych, ale gdybym zrobił coś takiego, z pewnością skomentowałbym to, żeby ludzie wiedzieli, co robię i dlaczego.

+0

niesamowite, dzięki. Dwa razy wznowiłbym głosowanie, gdybym mógł –

+0

+1 za cytowanie standardu (i odpowiadając na pytanie), dodając jednocześnie komentarz na temat stylu – Gabe

0

Nie używaj |= i &= z boolami. Mogą pracować przez większość czasu, ale wciąż jest źle. Zwykle typ bool jest po prostu uwielbionym int lub char. W starszym kodzie, nad którym pracowałem, BOOL jest po prostu wpisany jako int lub char. W takich przypadkach można uzyskać błędną odpowiedź, jeśli w jakiś sposób manipulowano bitami (na przykład 1&2 ma wartość 0 (fałsz)). I nie jestem pewien, ale myślę, że wynik operatorów bitowych będzie int, nawet dla boolów.

+0

myśli na + =? –

+3

Jeśli obie zmienne są zadeklarowane jako '' bool' ', to w jakich okolicznościach (inne niż uszkodzony kompilator lub niestandardowy kompilator), czy nie pójdą źle? –

+0

jeśli cokolwiek kiedykolwiek zostanie przekazane jako pustka * lub coś takiego, i masz API używające typu jako int, nie można zagwarantować, że zawsze będą używać "1" jako prawdziwego, w przeciwieństwie do jakiegokolwiek innego -zero całkowita. – Kip

0
if (!old_value) 
    old_value = possible_new_value; 

Jest to bezpośredni odpowiednik oryginalnego stanu. Może generować prostszy kod, ponieważ nie zawsze będzie przypisywany do old_value - ale nie spodziewam się, że różnica wydajności będzie łatwo mierzalna w dużym programie.

0

Jedna różnica polega na tym, że operatory logiczne, takie jak ||, gwarantują kolejność oceny i zapewniają zwarcie, gdzie operatory bitowe i operatory arytmetyczne tego nie robią.

Wierzę, że kompilator będzie traktował operatory nielogiczne, konwertując je do wartości numerycznych (0, 1), stosując operator i konwertując z powrotem. Konwersje te są ściśle określone przez standard, np .:

Wartość rytmu arytmetycznego, wyliczenia, wskaźnika lub wskaźnika na typ pręta może zostać przekonwertowana na wartość rangi typu bool. Wartość zerowa, zerowa wartość wskaźnika lub wartość wskaźnika elementu zerowego jest konwertowana na wartość false, każda inna wartość jest konwertowana na wartość true.

1

Czy możesz po prostu użyć operatora trójskładnikowego?

old_value = !old_value ? possible_new_value : old_value;

+0

dlaczego byłoby to preferowane do krótszej 'old_value = old_value || nowa_wartość; '? – Kip

+1

Wydaje mi się, że przeczytałem to pytanie źle :) Nie ma powodu, aby to robić zamiast 'old_value = old_value || nowa_wartość; ', zwłaszcza, że ​​ta ostatnia jest bardziej czytelna. – Cinder6

0

Nasty makro hackery:

#define UPDATE(x) x = x 

UPDATE(old_value) || possible_new_value; 

Ale ja nie polecam tego. Takie makra są bardzo złym pomysłem z kilku powodów.

Bardziej rozsądna funkcja, ale bez zwarcia:

bool set_or(bool &old, bool value) { 
    return (old = old || value); 
} 

... 

bool v = false; 
set_or(v, true); 
+0

Oczywiście działa to tylko wtedy, gdy x jest zmienną, i nie udaje się oczywiście, gdy x nie kończy się l-końcem, i zależy przede wszystkim od skonstruowania wyrażenia w połowie i na połowie makra. Ewwwww. –

+0

To makro nie powiedzie się, jeśli ocena "możliwa_nazw_wartość" ma skutek uboczny. –

+0

Jeśli zawiedzie, zależy od tego, jaka powinna być właściwa semantyka '|| ='. Nie jestem do końca pewien, czy zamierzano w tym celu sprowadzić zwarcia. – sth

4

Standardowe sayeth:

4.5-4 "Zintegrowany promocji"

rvalue typu bool można przekształca się rvalue typu int FALSE się zerem i prawdziwe stając się jednym.

5.17-7 "podmiot" przypisania

Zachowanie wyraz postaci op = E1 E2 odpowiada E1 = E1, E2, z tym, że PO E1 jest oceniany tylko pewnego razu. W + = i - =, E1 musi być albo mieć typ arytmetyczny, albo być wskaźnikiem dla potencjalnie zakwali fi kowanego w pełni zdefiniowanego typu obiektu. We wszystkich innych przypadkach E1 będzie mieć typ arytmetyczny .

4.12-1 "logiczne konwersji"

rvalue arytmetyczne, wyliczenie, wskaźnika lub kursora na typu człon może być przekształcony w rvalue typu bool. Wartość zerowa, zerowa wartość wskaźnika lub wartość wskaźnika elementu zerowego to skonwertowana na wartość false; każda inna wartość to skonwertowana na wartość true.

Więc to oznacza, że ​​

b1 += b2 

Gdzie B1 i B2 są logiczna będzie równoważna

b1 = b1 + b2 

i B1 i B2 będzie promowany do 0/1 całkowitych, a następnie przekształcane z powrotem do boolean z regułą, że wszystko inne niż 0 jest prawdziwe.

więc tabela Prawda jest

 
      true false 
true  true true 
false true false 

tak + = robi w rzeczywistości pracy jako || = zgodnie z normą. Prawdopodobnie będzie to jednak mylące innych programistów, więc chciałbym tego uniknąć.

+0

Niezłe włączenie 5.17-7. –

+0

+1 za cytowanie standardu, oraz za wyraźne rozbicie na + =, i za poradę, aby uniknąć + =. –

0

Wierzę, że standard jawnie definiuje true i false jako 1 i 0, więc można bezpiecznie używać operatorów bitowych na wartościach bool. Inne typy, które mogą być niejawnie traktowane jako zmiany w innym kontekście, powinny zostać jawnie przekonwertowane, aby działały niezawodnie.

Zauważyłem, że kompilator Microsoftu generuje brzydkie ostrzeżenie za każdym razem, gdy to robisz, ponieważ uważa, że ​​istnieje niebezpieczeństwo niejawnej zamiany wyniku z powrotem na wartość bool.

Powiązane problemy