Коротка відповідь
Всі оператори +=, -=, *=, /=, &=, |=... є арифметичними і забезпечують таке ж очікування:
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();