为什么 C++ 没有 &&= 或 ||= 来表示布尔值?
-
21-09-2019 - |
题
有没有 “非常糟糕的事情” 可能会发生 &&= 和 ||= 被用作语法糖 bool foo = foo && bar
和 bool foo = foo || bar
?
解决方案
A bool
可能只是 true
或者 false
在C++中。因此,使用 &=
和 |=
相对安全(尽管我不太喜欢这个符号)。确实,它们将执行位操作而不是逻辑操作(因此它们不会短路),但这些位操作遵循明确定义的映射,这实际上相当于逻辑操作, 只要 两个操作数都是类型 bool
.1
与其他人在这里所说的相反, 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
. 。IE。就像是
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()
总是被调用),&=
足够了:
示例 &=
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
======================
结论
所以 是的 我们可以替换 &&
经过 &
为了 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();