为什么C ++的布尔值没有&& =或|| =?


126

是否有一个“非常糟糕的事情”,可以发生&&=||=被用作语法糖bool foo = foo && barbool foo = foo || bar


5
看到另一个问题:stackoverflow.com/questions/2324549/…那是关于Java的,但是共享C世系,大多数情况下都使用相同的参数。
jamesdlin

基本上,只是c ++没有b / c,他们没有把它放在-像Ruby这样的语言中就没有。嘘...
Kache

2
但是在Ruby中,任何类型的x ||= y代码都大致不等同于C ++ x = x ? x : y;吗?换句话说,“如果尚未设置,则设置为y”。这比C或C ++有用得多x ||= y(禁止运算符重载)将“将x设置为,(bool)y除非已经设置”。我并不急于为此添加另一个运算符,这似乎有点虚弱。只是写if (!x) x = (bool)y。但是,然后,我并没有真正使用bool足够多的变量来希望额外的运算符仅对那种类型有用。
史蒂夫·杰索普

1
我敢肯定C ++不存在的主要原因,&&=或者||=仅仅是C没有它们。我可以肯定地确定C没有它们的原因是该功能还不够有益。
乔纳森·勒夫勒

2
同样,由于是超学究的,因此该符号bool foo = foo || bar;会调用未定义的行为,因为foo未在评估之前将其初始化foo || bar。当然,这应该是类似的bool foo = …initialization…; …; foo = foo || bar;,然后问题就成立了。
乔纳森·勒夫勒

Answers:


73

A bool只能是truefalse使用C ++。因此,使用&=|=是相对安全的(即使我不太喜欢这种表示法)。是的,它们将执行位运算而不是逻辑运算(因此不会短路),但是这些位运算遵循定义良好的映射,只要两个操作数的类型均bool有效,则映射等效于逻辑运算。1个

与其他人在这里所说的相反bool,C ++中的绝对不能具有不同的值,例如2。当将该值分配给时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!)

但是由于此代码仍然导致未定义的行为,因此我们可以放心地忽略遵循C ++代码的潜在问题。


1诚然,这是一个相当大的警告,正如Angew的评论所说明的那样:

bool b = true;
b &= 2; // yields `false`.

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


4
但是&&和|| 运算符将处理转换为bool的所有内容,而不仅仅是bool。
2010年

13
他们不会做同样的事情,即使是傻瓜。||&&快捷方式,即,在第二个参数不是操作数,如果第一操作数是true(相应的false&&)。|&|=&=始终评估两个操作数。
Niki 2010年

4
这不能回答为什么&& =和|| =不是c ++运算符的问题。

9
这是使用安全&=类型的左手侧bool,因为这是完全可能的是,右侧为比其他类型的bool(例如islower或其它C STDLIB函数返回非零为真值)。如果我们有假设&&=,则可能会迫使右侧转换为bool,而&=不会。换句话说,bool b = true; b &= 2;结果为b == false
Angew不再

2
@安东尼奥艰难的人群。😝
康拉德·鲁道夫

44

&&&具有不同的语义:&&如果第一个操作数为,则不会计算第二个操作数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();

35
在我看来,更需要&& =的原因。= P
卡切(Kache)2010年

4
不过,这并不是真正的答案。
Catskul

27

简短答案

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

x &= foo()  // We expect foo() be called whatever the value of x

但是,运算符&&=||=是合乎逻辑的,并且这些运算符可能容易出错,因为许多开发人员希望foo()总是调用in 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();

13
如果我真的想要这种行为怎么办?如果左手表达式错误,则不执行右手表达式。两次写入变量很烦人,例如success = success && DoImportantStuff()
Niklas R

1
我的建议是写if(success) success = DoImportantStuff()。如果success &&= DoImportantStuff()允许该语句,那么许多开发人员都会认为DoImportantStuff()总是被称为success。希望这能回答您想知道的问题...我也改善了部分答案。请告诉我我的答案现在是否更容易理解?(关于您的评论目的)干杯,见;-)
olibre

9
“如果success &&= DoImportantStuff()允许发表声明,那么许多开发人员都会认为,DoImportantStuff()无论成功的价值是什么,它总是被称为”。你可以这样说if (success && DoImportantStuff())。只要他们记住if语法背后的逻辑,就应该不会遇到麻烦&&=
pilkch 2014年

2
我看不到人们怎么可能会认为f1()总是用来评估,ok &&= f(1) 而不会假设它总是用来评估ok = ok && f(1)。对我来说似乎也一样。
einpoklum '16

1
我实际上期望 变量v1和表达式e2 v1 += e2的语法糖等效v1 = v1 + e1。只是一种简写形式,仅此而已。
einpoklum 2016年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.