Почему в c++ нет & & = или ||= для булевых значений?
есть "очень плохо" это может произойти & & = и | / = были использованы в качестве синтаксического сахара для bool foo = foo && bar
и bool foo = foo || bar
?
3 ответа:
A
bool
может быть толькоtrue
илиfalse
в C++. Как таковой,используя&=
и|=
- это совершенно безопасно (хотя мне не особенно нравится обозначение). Правда, они будут выполнять битовые операции, а не логические операции (и, следовательно, они не будут короткими замыканиями), но эти битовые операции следуют четко определенному отображению, которое фактически эквивалентно логическим операциям,пока оба операнда имеют типbool
.1вопреки тому, что здесь говорили другие люди, a
bool
в C++ никогда не должно быть другого значения, такого как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!)
но так как этот код приводит к неопределенному поведению в любом случае, мы можем смело игнорировать этот потенциал проблема в соответствии кода C++.
1 по общему признанию, это довольно большая оговорка, как показывает комментарий Angew:
bool b = true; b &= 2; // yields `false`.
причина в том, что
b & 2
выполняет целочисленное продвижение таким образом, что выражение тогда эквивалентноstatic_cast<int>(b) & 2
, в результате0
, который затем преобразуется обратно вbool
. Так что это правда, что существованиеoperator &&=
позволит повысить безопасность типов.
&&
и&
имеют разную семантику:&&
не вычисляет второй операнд, если первый операнд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();
короткий ответ:
все операторы
+=
,-=
,*=
,/=
,&=
,|=
... являются арифметическими и обеспечивают такое же ожидание:операторы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()
чтобы всегда называться),&=
is достаточно:пример
&=
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 ======================
вывод
да мы можем заменить&&
by&
наbool
значения ;-)
Так что лучше использовать&=
вместо&&=
.
Мы можем рассмотреть&&=
как бесполезно для булевых значений.то же самое для
||=
оператор
|=
менее ошибки чем||=
если a разработчик хочет
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();