是否有任何理由不在C++中对"bool"值使用按位运算符&,|和^?
我有时会遇到两个条件中只有一个是真的(XOR)的情况,所以我只是将^运算符抛出到条件表达式中.我有时也希望评估条件的所有部分是否结果是真的(而不是短路),所以我使用&和|.我有时也需要累积布尔值,而且&=和| =非常有用.
这样做时我已经有了一些眉毛,但代码仍然比其他方面更有意义和更清洁.是否有任何理由不将这些用于布尔?是否有任何现代编译器会给出不好的结果?
||
并且&&
是布尔运算符,内置的运算符保证返回true
或者false
.没有其他的.
|
,&
并且^
是按位运算符.当你操作的数字域只有1和0时,它们完全相同,但是如果你的布尔值不是严格的1和0 - 就像C语言一样 - 你可能最终会遇到一些行为你不想要.例如:
BOOL two = 2; BOOL one = 1; BOOL and = two & one; //and = 0 BOOL cand = two && one; //cand = 1
在C++中,然而,bool
类型保证是唯一的或者是true
或false
(分别隐含地转换为1
和0
),所以它的少,从这一立场令人担忧的,但人们还不习惯看到的代码这样的事情的事实没有做到这一点是一个很好的理由.只是说b = b && x
并完成它.
两个主要原因.总之,要仔细考虑; 可能有一个很好的理由,但是如果你的评论中有非常明确的,因为它可能很脆弱,正如你自己说的那样,人们通常不习惯看到这样的代码.
首先,如果你是在比其它值运行false
和true
(或0
和1
,为整数)时,^
运营商可以引入行为并不等同于逻辑XOR.例如:
int one = 1; int two = 2; // bitwise xor if (one ^ two) { // executes because expression = 3 and any non-zero integer evaluates to true } // logical xor; more correctly would be coded as // if (bool(one) != bool(two)) // but spelled out to be explicit in the context of the problem if ((one && !two) || (!one && two)) { // does not execute b/c expression = ((true && false) || (false && true)) // which evaluates to false }
感谢用户@Patrick首先表达了这一点.
二是|
,&
和^
,如位运算符,不会短路.此外,在单个语句中链接在一起的多个按位运算符 - 即使使用明确的括号 - 也可以通过优化编译器进行重新排序,因为所有3个操作通常都是可交换的.如果操作的顺序很重要,这一点很重要.
换一种说法
bool result = true; result = result && a() && b(); // will not call a() if result false, will not call b() if result or a() false
并不总是给出相同的结果(或结束状态)
bool result = true; result &= (a() & b()); // a() and b() both will be called, but not necessarily in that order in an // optimizing compiler
因为你可能无法控制的方法,这一点尤为重要a()
和b()
,或其他人可能会沿着后来改变他们不理解的依赖性,并造成讨厌(而且经常发布版本只)错误.
我认为
a != b
是你想要的
凸起的眉毛应该足以让你停止这样做.您不编写编译器的代码,首先为其他程序员编写代码,然后编写代码.即使编译器工作,令人惊讶的是其他人并不是你想要的 - 按位操作符不是用于bool操作.
我想你也用叉子吃苹果?它有效,但它给人们带来惊喜,所以最好不要这样做.
你问:
"有什么理由不使用的位运算符
&
,|
以及^
为'在C++布尔’值?"
是的,逻辑运算符,即内置的高级布尔运算符!
,&&
并||
提供以下优点:
保证将参数转换为bool
,即为0
和1
有序值.
保证短路评估,一旦最终结果已知,表达式评估就会停止.
这可以解释为树值逻辑,具有True,False和Indeterminate.
可读文本等价物not
,and
并且or
,即使我不使用他们自己.
正如读者锑的评论也指出了位级运营商的替代标记,即bitand
,bitor
,xor
和compl
,但在我看来,这些都是小于可读性and
,or
和not
.
简而言之,高级运算符的每个这样的优点都是位级运算符的缺点.
特别是,由于按位运算符缺少参数转换为0/1,因此得到eg 1 & 2
→ 0
,而1 && 2
→ true
.此外^
,按位排他或,可能以这种方式行为不端.被视为布尔值1和2是相同的,即true
,但被视为位图,它们是不同的.
然后,您提供一些问题的背景,
"我有时遇到两种情况中只有一种情况要求为真(XOR)的情况,所以我只是将^运算符抛出一个条件表达式."
嗯,按位运算符的优先级高于逻辑运算符.这尤其意味着在诸如的混合表达中
a && b ^ c
你得到了意想不到的结果a && (b ^ c)
.
而只是写
(a && b) != c
更简明扼要地表达你的意思.
对于多个参数要么/或没有C++运算符来完成这项工作.例如,如果你写的a ^ b ^ c
不是那不是,说:"是表达式a
,b
或者c
是真实的".相反,它说,"奇数a
,b
并且c
是真的",可能是其中1个或全部3 ...
要表达一般/或何时a
,b
以及c
类型bool
,只需写
(a + b + c) == 1
或者,使用非bool
参数,将它们转换为bool
:
(!!a + !!b + !!c) == 1
&=
积累的布尔结果.
你进一步阐述,
"我还需要积累,有时布尔值,并且
&=
和|=?
是非常有用的."
嗯,这相当于检查是否满足所有或任何条件,de Morgan定律告诉你如何从一个到另一个.即你只需要其中一个.你原则上可以使用*=
作为一个操作&&=
符(对于旧的George Boole发现,逻辑和很容易表示为乘法),但我认为那会困扰并可能误导代码的维护者.
还要考虑:
struct Bool { bool value; void operator&=( bool const v ) { value = value && v; } operator bool() const { return value; } }; #includeint main() { using namespace std; Bool a = {true}; a &= true || false; a &= 1234; cout << boolalpha << a << endl; bool b = {true}; b &= true || false; b &= 1234; cout << boolalpha << b << endl; }
使用Visual C++ 11.0和g ++ 4.7.1输出:
true false
结果不同的原因是bitlevel &=
不提供bool
其右侧参数的转换.
那么,您希望使用哪些结果&=
?
如果是前者,true
则更好地定义运算符(例如,如上所述)或命名函数,或者使用右侧表达式的显式转换,或者完全写入更新.