为什么不可以?布尔值有 &&= 或 ||= 吗?

发布于 2024-08-26 04:50:15 字数 206 浏览 3 评论 0原文

是否有可能发生“非常糟糕的事情”&&=并且||= 被用作 bool foo = foo && 的语法糖。 barbool foo = foo ||酒吧?

Is there a "very bad thing" that can happen &&= and ||= were used as syntactic sugar for bool foo = foo && bar and bool foo = foo || bar?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

猫瑾少女 2024-09-02 04:50:15

在 C++ 中,bool 只能为 truefalse。因此,使用 &=|= 相对安全(尽管我不太喜欢这种表示法)。确实,它们将执行位操作而不是逻辑操作(因此它们不会短路),但这些位操作遵循明确定义的映射,这实际上相当于逻辑操作,只要因为两个操作数都是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(b) & 2,结果为 0,然后将其转换回 bool。因此,运算符 &&= 的存在确实会提高类型安全性。

A bool may only be true or false in C++. As such, using &= and |= is relatively safe (even though I don’t particularly like the notation). True, they will perform bit operations rather than logical operations (and thus they won’t short-circuit) but these bit operations follow a well-defined mapping, which is effectively equivalent to the logical operations, as long as both operands are of type bool.1

Contrary to what other people have said here, a bool in C++ must never have a different value such as 2. When assigning that value to a bool, it will be converted to true as per the standard.

The only way to get an invalid value into a bool is by using reinterpret_cast on pointers:

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

But since this code results in undefined behaviour anyway, we may safely ignore this potential problem in conforming C++ code.


1 Admittedly this is a rather big caveat as Angew’s comment illustrates:

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

The reason is that b & 2 performs integer promotion such that the expression is then equivalent to static_cast<int>(b) & 2, which results in 0, which is then converted back into a bool. So it’s true that the existence of an operator &&= would improve type safety.

诠释孤独 2024-09-02 04:50:15

&&& 具有不同的语义:如果第一个操作数是 && 将不会计算第二个操作数假。即类似的东西

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();

&& and & have different semantics: && will not evaluate the second operand if the first operand is false. i.e. something like

flag = (ptr != NULL) && (ptr->member > 3);

is safe, but

flag = (ptr != NULL) & (ptr->member > 3);

is not, although both operands are of type bool.

The same is true for &= and |=:

flag = CheckFileExists();
flag = flag && CheckFileReadable();
flag = flag && CheckFileContents();

will behave differently than:

flag = CheckFileExists();
flag &= CheckFileReadable();
flag &= CheckFileContents();
花落人断肠 2024-09-02 04:50:15

简短回答

所有运算符 +=-=*=/=& =|=... 是算术并提供相同的期望:

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

但是,运算符 &&=||= > 是符合逻辑的,并且这些运算符可能容易出错,因为许多开发人员希望始终在 x &&= foo() 中调用 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(); 其中,仅当 f1() 返回 true 时才会调用 f2()

  • 如果开发人员实际上希望仅当 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
======================

结论

因此 YES 我们可以将 && 替换为 & 来表示 bool< /code> 值 ;-)
因此最好使用 &= 而不是 &&=
我们可以认为 &&= 对于布尔值来说是无用的。

||= 相同

运算符|=也比||=更不容易出错

如果开发人员希望调用 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();

Short answer

All the operators +=, -=, *=, /=, &=, |=... are arithmetic and provide same expectation:

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

However, operators &&= and ||= would be logical, and these operators might be error-prone because many developers would expect foo() be always called 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
  • Do we really need to make C/C++ even more complex to get a shortcut for x = x && foo()?

  • Do we really want to obfuscate more the cryptic statement x = x && foo()?
    Or do we want to write meaningful code like if (x) x = foo();?


Long answer

Example for &&=

If &&= operator was available, then this code:

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

is equivalent to:

bool ok = true;
if (ok) ok = f1();
if (ok) ok = f2(); //f2() is called only when f1() returns true

This first code is error-prone because many developers would think f2() is always called whatever the f1() returned value. It is like writing bool ok = f1() && f2(); where f2() is called only when f1() returns true.

  • If the developer actually wants f2() to be called only when f1() returns true, therefore the second code above is less error-prone.
  • Else (the developer wants f2() to be always called), &= is sufficient:

Example for &=

bool ok = true;
ok &= f1();
ok &= f2(); //f2() always called whatever the f1() returned value

Moreover, it is easier for compiler to optimize this above code than that below one:

bool ok = true;
if (!f1())  ok = false;
if (!f2())  ok = false;  //f2() always called

Compare && and &

We may wonder whether the operators && and & give the same result when applied on bool values?

Let's check using the following C++ code:

#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);
}

Output:

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
======================

Conclusion

Therefore YES we can replace && by & for bool values ;-)
So better use &= instead of &&=.
We can consider &&= as useless for booleans.

Same for ||=

operator |= is also less error-prone than ||=

If a developer wants f2() be called only when f1() returns false, instead of:

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 ...

I advice the following more understandable alternative:

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)

or if you prefer all in one line style:

// 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();
街道布景 2024-09-02 04:50:15

短路很重要,而且语义也很简单。 A &&= B 是 A = A && 的语法糖。 B.

单子编程的概念在 K&R 早期并不普遍,所以最好的解释似乎是 K&R 认为它并不重要,就像 QWERTY 键盘一样,我们一直忍受着它自从。

short circuiting is important, and the semantics are straightforward. A &&= B would be syntactic sugar for A = A && B.

The concept of monadic programming was not widespread in the early days of K&R, so it seems the best explanation is K&R didn't think it was important, and like the QWERTY keyboard, we've lived with it ever since.

娇妻 2024-09-02 04:50:15

我很惊讶没有人提到它:利用 bool 类型的隐式整数转换允许您伪造 &&=||=< /code> 分别为 *=+=

因此,以下内容按预期工作(使用 *= 而不是 &&=)并且非常有用:

bool is_ok = true;
is_ok *= check_this();
is_ok *= check_that();
is_ok *= check_something_else();
if (is_ok) std::cout << "all is well";

I'm surprised that nobody mentioned it: taking advantage of implicit integer conversion of the type bool allows you to fake &&= and ||= with *= and +=, respectively.

So, the following works as expected (using *= instead of &&=) and can be quite useful:

bool is_ok = true;
is_ok *= check_this();
is_ok *= check_that();
is_ok *= check_something_else();
if (is_ok) std::cout << "all is well";
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文