Krótka odpowiedź
Wszyscy operatorzy +=
, -=
, *=
, /=
, &=
, |=
... są arytmetyczny i zapewnić taką samą oczekiwania:
x &= foo() // We expect foo() be called whatever the value of x
Jednak operatory &&=
i ||=
byłyby logiczne, a operatory te mogą być podatne na błędy, ponieważ wielu programistów spodziewa foo()
się, że będą zawsze wywoływani x &&= foo()
.
bool x;
// ...
x &&= foo(); // Many developers might be confused
x = x && foo(); // Still confusing but correct
x = x ? foo() : x; // Understandable
x = x ? foo() : false; // Understandable
if (x) x = foo(); // Obvious
Czy naprawdę musimy uczynić C / C ++ jeszcze bardziej złożonym, aby uzyskać skrót x = x && foo()
?
Czy naprawdę chcemy bardziej zaciemnić tajemnicze stwierdzenie x = x && foo()
?
A może chcemy napisać znaczący kod if (x) x = foo();
?
Długa odpowiedź
Przykład dla &&=
Jeśli &&=
operator był dostępny, to ten kod:
bool ok = true; //becomes false when at least a function returns false
ok &&= f1();
ok &&= f2(); //we may expect f2() is called whatever the f1() returned value
jest równa:
bool ok = true;
if (ok) ok = f1();
if (ok) ok = f2(); //f2() is called only when f1() returns true
Ten pierwszy kod jest podatny na błędy, ponieważ wielu programistów pomyślałoby, że f2()
jest zawsze wywoływany niezależnie od f1()
zwracanej wartości. To tak, jakby pisać, bool ok = f1() && f2();
gdzie f2()
jest wywoływane tylko wtedy, gdy f1()
zwraca true
.
- Jeśli programista faktycznie chce,
f2()
aby wywoływano go tylko wtedy , gdy f1()
zwraca true
, drugi kod powyżej jest mniej podatny na błędy.
- W przeciwnym razie (programista chce,
f2()
aby zawsze dzwoniono), &=
wystarczy:
Przykład dla &=
bool ok = true;
ok &= f1();
ok &= f2(); //f2() always called whatever the f1() returned value
Co więcej, kompilatorowi łatwiej jest zoptymalizować powyższy kod niż poniższy:
bool ok = true;
if (!f1()) ok = false;
if (!f2()) ok = false; //f2() always called
Porównaj &&
i&
Możemy się zastanawiać, czy operatory &&
i &
dają taki sam wynik, gdy są stosowane na bool
wartościach?
Sprawdźmy, używając następującego kodu C ++:
#include <iostream>
void test (int testnumber, bool a, bool b)
{
std::cout << testnumber <<") a="<< a <<" and b="<< b <<"\n"
"a && b = "<< (a && b) <<"\n"
"a & b = "<< (a & b) <<"\n"
"======================" "\n";
}
int main ()
{
test (1, true, true);
test (2, true, false);
test (3, false, false);
test (4, false, true);
}
Wynik:
1) a=1 and b=1
a && b = 1
a & b = 1
======================
2) a=1 and b=0
a && b = 0
a & b = 0
======================
3) a=0 and b=0
a && b = 0
a & b = 0
======================
4) a=0 and b=1
a && b = 0
a & b = 0
======================
Wniosek
Dlatego TAK możemy zastąpić &&
przez &
do bool
wartości ;-)
Więc lepiej używać &=
zamiast &&=
.
Możemy uznać &&=
za bezużyteczne dla wartości logicznych.
To samo dotyczy ||=
operator |=
jest również mniej podatny na błędy niż||=
Jeśli programista chce f2()
być wywoływany tylko wtedy , gdy f1()
zwraca false
, zamiast:
bool ok = false;
ok ||= f1();
ok ||= f2(); //f2() is called only when f1() returns false
ok ||= f3(); //f3() is called only when f1() or f2() return false
ok ||= f4(); //f4() is called only when ...
Radzę następującą, bardziej zrozumiałą alternatywę:
bool ok = false;
if (!ok) ok = f1();
if (!ok) ok = f2();
if (!ok) ok = f3();
if (!ok) ok = f4();
// no comment required here (code is enough understandable)
lub jeśli wolisz wszystko w jednym stylu:
// this comment is required to explain to developers that
// f2() is called only when f1() returns false, and so on...
bool ok = f1() || f2() || f3() || f4();