为什么c ++没有&& =或|| =布尔值?
是否有一个“非常糟糕的事情”可以发生&& =和|| =作为语法糖用于bool foo = foo && bar
和bool foo = foo || bar
bool foo = foo || bar
?
一个bool
可能只是在C + +的true
或false
。 因此, 使用&=
和|=
是完全安全的 (即使我不特别喜欢这个符号)。 诚然,它们将执行位操作而不是逻辑运算(因此它们不会短路),但是这些位操作遵循一个定义良好的映射,这个映射实际上等同于逻辑操作, 只要这两个操作数是types的bool
。 1
与其他人在这里所说的相反,C ++中的bool
值不能有不同的值,例如2
。 当把这个值bool
一个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
执行整数提升,因此expression式等同于static_cast<int>(b) & 2
,结果为0
,然后转换回bool
。 所以, operator &&=
的存在会提高types安全性。
&&
和具有不同的语义:如果第一个操作数为false
则&&
不会计算第二个操作数。 即类似的东西
flag = (ptr != NULL) && (ptr->member > 3);
是安全的,但是
flag = (ptr != NULL) & (ptr->member > 3);
不是,尽pipe两个操作数都是bool
types的。
&=
和|=
也是如此:
flag = CheckFileExists(); flag = flag && CheckFileReadable(); flag = flag && CheckFileContents();
将performance不同于:
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
这第一个代码是容易出错的,因为许多开发人员会认为无论f1()
返回的值如何都会调用f2()
。 这就像写作bool ok = f1() && f2();
其中f2()
仅在f1()
返回true
时被调用。
- 如果开发人员实际上只想在
f1()
返回true
时调用f2()
,那么上面的第二个代码就不太容易出错。 - 否则(开发人员需要始终调用
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 ======================
结论
因此,我们可以用&&
replace&&
作为bool
值;-)
所以最好使用&=
而不是&&=
。
我们可以认为&&=
对布尔值是无用的。
同样的||=
运算符
|=
也比||=
更less出错
如果开发人员只在f1()
返回false
时调用f2()
,而不是:
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 ...
我build议下面更容易理解的select:
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();