Ответ 1
Оператор !=
служит для этой цели для значений bool
.
Есть ли такая вещь? Это первый раз, когда я столкнулся с практической необходимостью, но я не вижу ни одного перечисленного в Struustrup. Я намерен написать:
// Detect when exactly one of A,B is equal to five.
return (A==5) ^^ (B==5);
Но нет оператора ^^
. Могу ли я использовать побитовый ^
здесь и получить правильный ответ (независимо от машинного представления true и false)? Я никогда не смешиваю &
и &&
, или |
и ||
, поэтому я не решаюсь сделать это с помощью ^
и ^^
.
Мне было бы удобнее писать собственную функцию bool XOR(bool,bool)
.
Оператор !=
служит для этой цели для значений bool
.
Для истинной логической операции XOR это будет работать:
if(!A != !B) {
// code here
}
Правильная логическая реализация XOR зависит от того, насколько тесно вы хотите имитировать общее поведение других логических операторов (||
и &&
) с помощью XOR. Есть две важные вещи об этих операторах: 1) они гарантируют оценку короткого замыкания, 2) вводят точку последовательности, 3) они оценивают свои операнды только один раз.
Оценка XOR, как вы понимаете, не может быть закорочена, поскольку результат всегда зависит от обоих операндов. Так что 1 не может быть и речи. Но как насчет 2? Если вам все равно 2, то с нормализованным (т.е. bool
) значением оператор !=
выполняет задание XOR по результату. При этом операнды можно легко нормализовать с помощью унарного !
. Таким образом, !A != !B
реализует правильный XOR в этом отношении.
Но если вам нужна дополнительная точка последовательности, ни !=
, ни побитовый ^
- это правильный способ реализации XOR. Один из возможных способов правильного выполнения XOR (a, b) может выглядеть следующим образом
a ? !b : b
Это на самом деле так близко, что вы можете сделать домашнее XOR "похожим" на ||
и &&
. Это будет работать, конечно, только если вы реализуете свой XOR в качестве макроса. Функция не будет выполняться, так как секвенирование не будет применяться к аргументам функции.
Кто-то может сказать, что единственная причина наличия точки последовательности в каждом &&
и ||
заключается в поддержке короткозамкнутой оценки, и, следовательно, XOR не нуждается в ней. На самом деле это имеет смысл. Тем не менее, стоит подумать о том, что XOR с точкой последовательности посередине. Например, следующее выражение
++x > 1 && x < 5
определил поведение и конкретный результат в C/С++ (по крайней мере, в отношении последовательности). Таким образом, можно разумно ожидать того же от пользовательского логического XOR, как в
XOR(++x > 1, x < 5)
в то время как XOR !=
не имеет этого свойства.
Есть другой способ сделать XOR:
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;
}
Оператор XOR не может быть закорочен; т.е. вы не можете предсказать результат выражения XOR, просто оценив его левый операнд. Таким образом, нет причин для предоставления версии ^^
.
Был добавлен хороший код, который решил проблему лучше, чем! 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 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
Используйте простой:
return ((op1 ? 1 : 0) ^ (op2 ? 1 : 0));
Я использую "xor" (похоже, это ключевое слово; в Code::Blocks по крайней мере он становится полужирным), так же, как вы можете использовать "и" вместо &&
и "или" вместо ||
.
if (first xor second)...
Да, это поразрядно. К сожалению.
Вот как я думаю, вы пишете сравнение XOR в С++:
bool a = true; // Test by changing to true or false
bool b = false; // Test by changing to true or false
if (a == !b) // THIS IS YOUR XOR comparison
{
// do whatever
}
Доказательство
XOR TABLE
a b XOR
--- --- ---
T T F
T F T
F T T
F F F
a == !b TABLE
a b !b a == !b
--- --- --- -------
T T F F
T F T T
F T F T
F F T F
Доказательство состоит в том, что исчерпывающее исследование входов и выходов показывает, что в двух таблицах для каждого входного набора результат всегда идентичен в двух таблицах.
Поэтому исходный вопрос заключается в том, как писать:
return (A==5) ^^ (B==5)
Ответ будет
return (A==5) == !(B==5);
Или, если хотите, напишите
return !(A==5) == (B==5);
#if defined(__OBJC__)
#define __bool BOOL
#include <stdbool.h>
#define __bool bool
#endif
static inline __bool xor(__bool a, __bool b)
{
return (!a && b) || (a && !b);
}
Он работает как определено. Условные выражения должны определить, используете ли вы Objective-C, который запрашивает BOOL вместо bool (длина отличается!)