有这样的东西吗?这是我第一次遇到对它的实际需求,但我在Stroustrup中没有看到它的列表。我打算写:
// Detect when exactly one of A,B is equal to five.
return (A==5) ^^ (B==5);
但是没有^^操作符。我可以使用这里的位^并得到正确的答案(不管机器表示的是真还是假)吗?我从不把&和&&混在一起,或者|和||混在一起,所以我不太愿意把^和^^混在一起。
我更愿意写我自己的bool XOR(bool,bool)函数。
异或还有另一种方式:
bool XOR(bool a, bool b)
{
return (a + b) % 2;
}
这显然可以通过以下方式来证明:
#include <iostream>
bool XOR(bool a, bool b)
{
return (a + b) % 2;
}
int main()
{
using namespace std;
cout << "XOR(true, true):\t" << XOR(true, true) << endl
<< "XOR(true, false):\t" << XOR(true, false) << endl
<< "XOR(false, true):\t" << XOR(false, true) << endl
<< "XOR(false, false):\t" << XOR(false, false) << endl
<< "XOR(0, 0):\t\t" << XOR(0, 0) << endl
<< "XOR(1, 0):\t\t" << XOR(1, 0) << endl
<< "XOR(5, 0):\t\t" << XOR(5, 0) << endl
<< "XOR(20, 0):\t\t" << XOR(20, 0) << endl
<< "XOR(6, 6):\t\t" << XOR(5, 5) << endl
<< "XOR(5, 6):\t\t" << XOR(5, 6) << endl
<< "XOR(1, 1):\t\t" << XOR(1, 1) << endl;
return 0;
}
正确的手动逻辑异或实现取决于您希望用异或模拟其他逻辑运算符(||和&&)的一般行为的程度。关于这些操作符有两个重要的事情:1)它们保证短路计算,2)它们引入序列点,3)它们只计算操作数一次。
正如您所理解的,异或求值不能被短路,因为结果总是取决于两个操作数。所以1是不可能的。那么2呢?如果你不关心2,那么对于规范化的(即bool)值,operator !=在结果方面完成XOR的工作。如果需要,操作数可以很容易地用unary !规范化。因此,A != !B在这方面实现了适当的异或。
但是如果你关心额外的序列点,无论是!=还是位^都不是实现异或的正确方法。正确执行异或(a, b)的一种可能方法如下所示
a ? !b : b
这实际上是你能得到的最接近于制作一个自制的异或“类似”||和&&。当然,这只有在将XOR作为宏实现时才会起作用。函数不会这样做,因为排序将不适用于函数的参数。
有人可能会说,在每个&&和||处都有序列点的唯一原因是为了支持短路求值,因此XOR不需要。实际上,这是有道理的。然而,考虑一个中间有序列点的异或是值得的。例如,下面的表达式
++x > 1 && x < 5
已经在C/ c++中定义了行为和特定的结果(至少在排序方面)。因此,用户定义的逻辑XOR可能也有相同的期望,如
XOR(++x > 1, x < 5)
而基于!=的异或没有此属性。
有一些好的代码比!a != !b更好地解决了这个问题
注意,我必须添加BOOL_DETAIL_OPEN/CLOSE,这样它才能在MSVC 2010上工作
/* From: http://groups.google.com/group/comp.std.c++/msg/2ff60fa87e8b6aeb
Proposed code left-to-right? sequence point? bool args? bool result? ICE result? Singular 'b'?
-------------- -------------- --------------- ---------- ------------ ----------- -------------
a ^ b no no no no yes yes
a != b no no no no yes yes
(!a)!=(!b) no no no no yes yes
my_xor_func(a,b) no no yes yes no yes
a ? !b : b yes yes no no yes no
a ? !b : !!b yes yes no no yes no
[* see below] yes yes yes yes yes no
(( a bool_xor b )) yes yes yes yes yes yes
[* = a ? !static_cast<bool>(b) : static_cast<bool>(b)]
But what is this funny "(( a bool_xor b ))"? Well, you can create some
macros that allow you such a strange syntax. Note that the
double-brackets are part of the syntax and cannot be removed! The set of
three macros (plus two internal helper macros) also provides bool_and
and bool_or. That given, what is it good for? We have && and || already,
why do we need such a stupid syntax? Well, && and || can't guarantee
that the arguments are converted to bool and that you get a bool result.
Think "operator overloads". Here's how the macros look like:
Note: BOOL_DETAIL_OPEN/CLOSE added to make it work on MSVC 2010
*/
#define BOOL_DETAIL_AND_HELPER(x) static_cast<bool>(x):false
#define BOOL_DETAIL_XOR_HELPER(x) !static_cast<bool>(x):static_cast<bool>(x)
#define BOOL_DETAIL_OPEN (
#define BOOL_DETAIL_CLOSE )
#define bool_and BOOL_DETAIL_CLOSE ? BOOL_DETAIL_AND_HELPER BOOL_DETAIL_OPEN
#define bool_or BOOL_DETAIL_CLOSE ? true:static_cast<bool> BOOL_DETAIL_OPEN
#define bool_xor BOOL_DETAIL_CLOSE ? BOOL_DETAIL_XOR_HELPER BOOL_DETAIL_OPEN