2009-08-18 21 views
5

我真正想要的是|| =运算符。bool与非布尔运算符的行为

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

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

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

old_value += possible_new_value; 
old_value |= possible_new_value; 

虽然我在这个问题上布尔如何与其他非布尔运算符行为?

- 
-= 
& 
&= 
... 

我可以验证这些经验,但我最感兴趣的是标准说什么。

回答

12

根据4.7(积分转化),第4段,“如果目标类型为bool,见4.12。如果源类型为bool,则值false将转换为零,并且值true将转换为一个。“在4.12中,”算术,枚举,指针或指向成员类型的指针可以转换为类型的右值bool。零值,空指针值或空成员指针值被转换为false;任何其他值被转换为true“。

bool操作数没有允许的,但整体的操作数,该bool将被转换为一个整数类型。当整数结果被存储在一个bool变量,它将一个上下文将其转换为bool

因此,您将能够使用+和*作为布尔或和和,并且您还可以使用|和&也不能脱离它们,因为(bool1 + bool2 )&如果所有三个变量都是true,则bool3将产生false。((1 + 1)& 1是2 & 1,这是0,或者是假的。)

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

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

+0

真棒,谢谢。如果我可以用 – 2009-08-18 17:22:06

+0

+1来引用标准(并回答问题),那么我会投票两次,同时也会添加有关样式 – Gabe 2009-08-18 17:23:09

0

请勿使用|=&=与bools。他们大部分时间都可以工作,但仍然是错误的。通常,bool类型只是一个荣耀的int或char。在我曾经使用过的较旧的代码中,BOOL只是将它定义为int或char。在这些情况下,如果某些位已被操纵(例如,1&2为0(false)),则可能得到错误的答案。我不确定,但我认为按位运算符的结果将是一个整数,即使对于布尔。

+0

想法+ =? – 2009-08-18 17:03:47

+3

如果两个变量都被声明为'bool',那么在什么情况下(除了破碎的编译器 - 或者非标准的,也就是预标准编译器),它们会出错吗? – 2009-08-18 17:04:29

+0

如果有任何事情被作为void *或某事传递,并且您有一个使用该类型的API作为int,则不能保证它们始终将使用“1”作为true,而不是其他任何非 - 零整数。 – Kip 2009-08-18 17:07:47

0
if (!old_value) 
    old_value = possible_new_value; 

这是原始状态的直接等价物。它可能会生成更简单的代码,因为它并不总是分配给old_value - 但我不希望性能差异在大型程序中很容易衡量。

0

一个区别是逻辑运算符(如||)保证评估的顺序并提供短路,其中按位和算术运算符不这样做。

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

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

1

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

old_value = !old_value ? possible_new_value : old_value;

+0

为什么会选择较短的'old_value = old_value || new_value;'? – Kip 2009-08-18 19:22:59

+1

似乎我读错了问题:)没有理由这样做,而不是'old_value = old_value || new_value;',尤其是因为后者更具可读性。 – Cinder6 2009-08-18 21:46:20

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); 
+0

当然,这只有当x是一个变量时才起作用,并且只有在x没有结束左值时才明显失败,并且非常依赖构建宏的一半和一半的表达式。 Ewwwww。 – 2009-08-18 17:17:24

+0

如果评估'possible_new_value'具有副作用,则此宏将失败。 – 2009-08-18 18:00:30

+0

如果失败取决于'|| ='的正确语义应该是什么。我真的不确定短路是否有意或无意。 – sth 2009-08-18 18:18:19

4

标准sayeth:

4.5-4 “整体促销”

bool类型的右值可以 转换为int类型, 的右值与假变为零和真 成为一个。

5.17-7 “赋值运算符”

的 形式E1运算的表达式的行为= E2相当于E1 = E1 E2运算除了E1只计算 一旦。在+ =和 - =中,E1应该具有算术类型,或者是指向完全定义的对象类型的可能合格的 指针。在所有 其他情况下,E1应具有算术 类型。

4.12-1“布尔转化”

算术,枚举 指针,或指向构件类型的右值可以 被转换成类型 布尔的右值。零值,空值指针 值或空成员指针值为 转换为false;任何其他值为 转换为true。

因此,这意味着

b1 += b2 

其中B1和B2是布尔将相当于

b1 = b1 + b2 

和B1和B2将晋升为0/1整数,然后转换回到布尔值规则,除了0以外的任何东西都是真的。

所以真值表

 
      true false 
true  true true 
false true false 

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

+0

的评论。好的包含5.17-7。 – 2009-08-18 17:22:05

+0

+1用于引用标准,并且用于+ =的明确分解以及用于避免+ =的建议。 – 2009-08-18 17:22:30

0

我相信标准明确定义true和false为1和0,所以你可以安全地使用位运算符bool值。其他可能被隐式视为另一个上下文中的bools的类型应该被明确地转换为可靠工作。

我见过微软的编译器在每次执行这个操作时都会生成一个丑陋的警告,因为它认为隐式地将int结果转换回bool是有危险的。