为什么c ++对于布尔值没有&& =或|| =?

Kac*_*che 115 c++ boolean-operations

有没有"非常糟糕的事情"可以发生&& =和|| =被用作语法糖bool foo = foo && barbool foo = foo || bar

Kon*_*lph 69

A bool可能只是truefalse在C++中.因此,使用&=|=相对安全(即使我不特别喜欢这种表示法).确实,它们将执行位操作而不是逻辑操作(因此它们不会短路)但这些位操作遵循明确定义的映射,这实际上等同于逻辑操作,只要两个操作数都是类型的bool.1

与其他人在这里所说的相反bool,C++必须永远不会有不同的价值,例如2.将该值分配给a时bool,它将true按照标准进行转换.

将无效值转换为a的唯一方法bool是使用reinterpret_caston指针:

int i = 2;
bool b = *reinterpret_cast<bool*>(&i);
b |= true; // MAY yield 3 (but doesn’t on my PC!)
Run Code Online (Sandbox Code Playgroud)

但是,由于此代码无论如何都会导致未定义的行为,因此我们可以安全地忽略这个符合C++代码的潜在问题.


1无可否认,这是一个相当大的警告,因为Angew的评论说明:

bool b = true;
b &= 2; // yields `false`.
Run Code Online (Sandbox Code Playgroud)

原因是b & 2执行整数提升,使得表达式等效static_cast<int>(b) & 2,然后导致0,然后将其转换回a bool.因此,确实存在operator &&=可以提高类型安全性.

  • 即使是布尔,他们也不会做同样的事情.`||`和`&&`快捷方式,即第二个参数不是操作数,如果第一个操作数是'true`(对于`&&`,则为'false`).`|`,`&`,`| =`和`&=`总是评估两个操作数. (13认同)
  • 使用`&=`作为`bool`类型的左侧是不安全的,因为右手边的类型完全可能是`bool`以外的类型(例如`islower`或另一个C stdlib函数,它返回非零值为真值).如果我们有假设的'&& =`,它可能会迫使右侧转换为`bool`,而`= =`则不会.换句话说,`bool b = true; b&= 2;`导致`b == false`. (9认同)
  • 这并没有回答为什么&& =和|| =不是c ++运算符的问题. (4认同)
  • 但是&&和|| 运营商将处理任何*转换*bool,而不仅仅是bool. (3认同)
  • @安东尼奥艰难的人群。 (2认同)

Nik*_*iki 44

&&并且&具有不同的语义:&&如果第一个操作数是,则不会计算第二个操作数false.即类似的东西

flag = (ptr != NULL) && (ptr->member > 3);
Run Code Online (Sandbox Code Playgroud)

是安全的,但是

flag = (ptr != NULL) & (ptr->member > 3);
Run Code Online (Sandbox Code Playgroud)

不是,虽然两个操作数都是类型bool.

同样是真实的&=|=:

flag = CheckFileExists();
flag = flag && CheckFileReadable();
flag = flag && CheckFileContents();
Run Code Online (Sandbox Code Playgroud)

将表现得与以下不同:

flag = CheckFileExists();
flag &= CheckFileReadable();
flag &= CheckFileContents();
Run Code Online (Sandbox Code Playgroud)

  • 在我看来,更有理由拥有&& =.= P (31认同)
  • 但这并不是真正的答案。 (4认同)

oli*_*bre 26

简短的回答

所有的运营商+=,-=,*=, /=,&=,|=...是算术,并提供同样的期望:

x &= foo()  // We expect foo() be called whatever the value of x
Run Code Online (Sandbox Code Playgroud)

但是,运算符&&=并且||=是合乎逻辑的,并且这些运算符可能容易出错,因为许多开发人员会期望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
Run Code Online (Sandbox Code Playgroud)
  • 我们真的需要让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
Run Code Online (Sandbox Code Playgroud)

相当于:

bool ok = true;
if (ok) ok = f1();
if (ok) ok = f2(); //f2() is called only when f1() returns true
Run Code Online (Sandbox Code Playgroud)

第一个代码容易出错,因为许多开发人员会认为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
Run Code Online (Sandbox Code Playgroud)

此外,编译器更容易优化上面的代码而不是下面的代码:

bool ok = true;
if (!f1())  ok = false;
if (!f2())  ok = false;  //f2() always called
Run Code Online (Sandbox Code Playgroud)

比较&&&

我们可能不知道经营者是否&&&何时施加给出相同的结果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);
}
Run Code Online (Sandbox Code Playgroud)

输出:

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
======================
Run Code Online (Sandbox Code Playgroud)

结论

因此我们可以更换&&&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 ...
Run Code Online (Sandbox Code Playgroud)

我建议以下更容易理解的替代方案:

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)
Run Code Online (Sandbox Code Playgroud)

或者如果你喜欢所有的一线风格:

// 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();
Run Code Online (Sandbox Code Playgroud)

  • 如果我真的想要这种行为怎么办?如果左手表达式错误,则不执行右手表达式.将变量写两次很烦人,比如`success = success && DoImportantStuff()` (13认同)
  • "如果允许声明`success && = DoImportantStuff()`,许多开发人员会认为`DoImportantStuff()`总是被称为成功的价值." 你可以说'if(success && DoImportantStuff())`.只要他们记住if语法背后的逻辑,他们应该没有问题`&& =`. (9认同)
  • 我看不到人们怎么会认为`f1()`总是在`ok &amp;&amp; = f(1)`中求值,但不会假设它总是在`ok = ok &amp;&amp; f(1)`中求值。对我来说似乎也一样。 (2认同)
  • 我实际上期望“v1 += e2”是变量 v1 和表达式 e2 的“v1 = v1 + e1”的语法糖。只是一个简写符号,仅此而已。 (2认同)