Есть ли "очень плохо" , которые могут случиться && = и || = были использованы в качестве синтаксического сахара для bool foo = foo && bar
и bool foo = foo || bar
?
Почему С++ не имеет && = или || = для booleans?
Ответ 1
A bool
может быть только true
или false
в С++. Таким образом, с использованием &=
и |=
абсолютно безопасен (хотя я не особенно люблю нотацию). Правда, они будут выполнять битовые операции, а не логические операции (и, следовательно, они не будут короткими), но эти битовые операции следуют четко определенному отображению, которое фактически эквивалентно логическим операциям, , пока оба операнда тип bool
. 1
Вопреки тому, что говорили другие люди, bool
в С++ никогда не должен иметь другое значение, например 2
. При присвоении этому значению bool
он будет преобразован в true
в соответствии со стандартом.
Единственный способ получить недопустимое значение в bool
заключается в использовании reinterpret_cast
для указателей:
int i = 2;
bool b = *reinterpret_cast<bool*>(&i);
b |= true; // MAY yield 3 (but doesn’t on my PC!)
Но так как этот код приводит к поведению undefined в любом случае, мы можем смело игнорировать эту потенциальную проблему в соответствии с кодом С++.
1 По общему признанию, это довольно большое оговорку, поскольку комментарий Ангуса иллюстрирует:
bool b = true;
b &= 2; // yields `false`.
Причина в том, что b & 2
выполняет целочисленное продвижение, так что выражение затем эквивалентно static_cast<int>(b) & 2
, что приводит к 0
, который затем преобразуется обратно в bool
. Поэтому его истинность в том, что существование operator &&=
улучшит безопасность типов.
Ответ 2
&&
и &
имеют другую семантику: &&
не будет оценивать второй операнд, если первый операнд false
. то есть что-то вроде
flag = (ptr != NULL) && (ptr->member > 3);
безопасен, но
flag = (ptr != NULL) & (ptr->member > 3);
нет, хотя оба операнда имеют тип bool
.
То же самое верно для &=
и |=
:
flag = CheckFileExists();
flag = flag && CheckFileReadable();
flag = flag && CheckFileContents();
будет вести себя иначе, чем:
flag = CheckFileExists();
flag &= CheckFileReadable();
flag &= CheckFileContents();
Ответ 3
Короткий ответ
Все операторы +=
, -=
, *=
, /=
, &=
, |=
... являются арифметическими и обеспечивают такое же ожидание:
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/С++ еще более сложным, чтобы получить ярлык для
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
, поэтому второй код выше менее подвержен ошибкам. - Else (разработчик хочет, чтобы
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
?
Проверить, используя следующий код С++:
#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
======================
Заключение
Поэтому ДА мы можем заменить &&
на &
на 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();