6

我真正想要的是一个 ||= 运算符。

old_value = old_value || possible_new_value;
old_value ||= possible_new_value;

第二行是编译器错误(c++ 没有 ||= 运算符)。

那么我的其他选择是什么?

old_value += possible_new_value;
old_value |= possible_new_value;

当我谈到这个主题时,bool 与其他非布尔运算符的行为如何?

-
-=
&
&=
...

我可以凭经验验证这些,但我最感兴趣的是标准所说的内容。

4

8 回答 8

13

根据 4.7(整数转换)第 4 段,“如果目标类型是bool,请参阅 4.12。如果源类型是bool,则将值false转换为 0 并将值true转换为 1。” 在 4.12 中,“算术、枚举、指针或指向成员类型的指针的右值可以转换为类型的右值bool。零值、空指针值或空成员指针值转换为false;任何其他值都转换为true。”

bool在不允许操作数但整数操作数的上下文中,bool将转换为整数类型。当整数结果存储在bool变量中时,它将被转换为bool.

因此,您将能够将 + 和 * 用作布尔值或与和,并且您可以使用 | 并且。您无法将它们混合在一起,因为 (bool1 + bool2) & bool3false如果所有三个变量都是true. ((1 + 1) & 1 是 2 & 1,也就是 0,否则为假。)

请记住 | 和 || 即使在这里也不一样。| 将评估双方,然后评估按位或。|| 将评估第一个操作数,然后只有当它为假时才会评估第二个。

我不打算在这里讨论风格问题,但如果我做了类似的事情,我一定会发表评论,以便人们知道我在做什么以及为什么。

于 2009-08-18T17:14:32.207 回答
4

标准说:

4.5-4“积分促销”

bool 类型的右值可以转换为 int 类型的右值,false 变为 0,true 变为 1。

5.17-7“赋值运算符”

形式为 E1 op= E2 的表达式的行为等价于 E1 = E1 op E2 ,只是 E1 只计算一次。在 += 和 -= 中,E1 要么具有算术类型,要么是指向可能 cvqualified 完全定义的对象类型的指针。在所有其他情况下,E1 应具有算术类型。

4.12-1“布尔转换”

算术、枚举、指针或指向成员类型的指针的右值可以转换为 bool 类型的右值。将零值、空指针值或空成员指针值转换为 false;任何其他值都将转换为 true。

所以这意味着

b1 += b2

其中 b1 和 b2 是布尔值将等价于

b1 = b1 + b2

b1 和 b2 将被提升为 0/1 整数,然后根据除 0 以外的任何值都为真的规则转换回布尔值。

所以真值表是

            真假
真的 真的 真的
假 真 假

所以 += 实际上根据标准作为 ||= 工作。但是,这可能会让其他程序员感到困惑,所以我仍然会避免它。

于 2009-08-18T17:18:55.567 回答
1

你可以只使用三元运算符吗?

old_value = !old_value ? possible_new_value : old_value;

于 2009-08-18T17:13:27.030 回答
0

不要使用|=&=与布尔值。他们可能大部分时间都在工作,但它仍然是错误的。通常 bool 类型只是一个美化的 int 或 char。在我使用过的旧代码中,BOOL 只是类型定义为 int 或 char。在这些情况下,如果以某种方式操纵了位(例如,1&2为 0(假)),您可能会得到错误的答案。而且我不确定,但我认为按位运算符的结果将是一个 int,即使对于布尔值也是如此。

于 2009-08-18T17:01:22.560 回答
0
if (!old_value)
    old_value = possible_new_value;

这是原始条件的直接等价物。它可能会生成更简单的代码,因为它不会总是分配给old_value- 但我不希望在大型程序中可以轻松测量性能差异。

于 2009-08-18T17:08:09.817 回答
0

一个区别是逻辑运算符如||保证评估顺序并提供短路,而按位和算术运算符则不能。

我相信编译器将通过将布尔值转换为数值 (0, 1) 应用运算符并转换回来来处理非逻辑运算符。这些转换由标准严格定义,例如:

算术、枚举、指针或指向成员类型的指针的右值可以转换为 bool 类型的右值。零值、空指针值或空成员指针值转换为假,任何其他值都转换为真。

于 2009-08-18T17:09:54.510 回答
0

讨厌的宏骇客:

#define UPDATE(x) x = x

UPDATE(old_value) || possible_new_value;

但我根本不推荐这个。出于几个原因,像这样的宏是一个非常糟糕的主意。

一个更健全的功能,但没有短路:

bool set_or(bool &old, bool value) {
  return (old = old || value);
}

...

bool v = false;
set_or(v, true);
于 2009-08-18T17:14:12.643 回答
0

我相信该标准将真假明确定义为 1 和 0,因此您可以安全地对bool值使用位运算符。在另一个上下文中可能被隐式视为布尔值的其他类型应显式转换以使其可靠地工作。

我看到 Microsoft 的编译器每次执行此操作时都会生成一个丑陋的警告,因为它认为将 int 结果隐式转换回 bool 存在危险。

于 2009-08-18T17:20:20.043 回答