Коротка відповідь
Всі оператори +=
, -=
, *=
, /=
, &=
, |=
... є арифметичними і забезпечують таке ж очікування:
x &= foo() // We expect foo() be called whatever the value of x
Однак оператори &&=
і ||=
будуть логічними, і ці оператори можуть бути схильними до помилок, тому що багато розробників сподіваються, foo()
що завжди зателефонують 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
Чи дійсно нам потрібно зробити C / C ++ ще складнішим, щоб отримати ярлик x = x && foo()
?
Невже ми хочемо більше придушити криптовалюту x = x && foo()
?
Або ми хочемо написати такий змістовний код if (x) x = foo();
?
Довга відповідь
Приклад для &&=
Якщо &&=
оператор був доступний, то цей код:
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
еквівалентно:
bool ok = true;
if (ok) ok = f1();
if (ok) ok = f2(); //f2() is called only when f1() returns true
Цей перший код схильний до помилок, оскільки багато розробників вважають, що f2()
його завжди називають незалежно від f1()
поверненого значення. Це як писати те, bool ok = f1() && f2();
куди f2()
дзвонять, лише коли f1()
повертаються true
.
- Якщо розробник насправді хоче
f2()
викликати лише тоді, коли f1()
повертається true
, тому другий код вище менш схильний до помилок.
- Іншого (розробник хоче,
f2()
щоб його завжди викликали), &=
достатньо:
Приклад для &=
bool ok = true;
ok &= f1();
ok &= f2(); //f2() always called whatever the f1() returned value
Крім того, компілятору простіше оптимізувати цей вище код, ніж цей:
bool ok = true;
if (!f1()) ok = false;
if (!f2()) ok = false; //f2() always called
Порівняйте &&
і&
Ми можемо задатися питанням, чи дають оператори &&
і &
той же результат при застосуванні до bool
значень?
Давайте перевіримо, використовуючи наступний код 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);
}
Вихід:
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
======================
Висновок
Тому YES ми можемо замінити &&
на &
для bool
значень ;-)
Так що краще використовувати &=
замість &&=
.
Ми можемо вважати &&=
марними булени.
Те саме для ||=
Оператор |=
також менш схильний до помилок, ніж||=
Якщо розробник хоче f2()
викликати лише тоді, коли f1()
повертається false
, а не:
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 ...
Я раджу наступну більш зрозумілу альтернативу:
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)
або якщо ви віддаєте перевагу всім в одному стилі рядка :
// 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();