Логический оператор XOR в С++?

Есть ли такая вещь? Это первый раз, когда я столкнулся с практической необходимостью, но я не вижу ни одного перечисленного в Struustrup. Я намерен написать:

// Detect when exactly one of A,B is equal to five.
return (A==5) ^^ (B==5);

Но нет оператора ^^. Могу ли я использовать побитовый ^ здесь и получить правильный ответ (независимо от машинного представления true и false)? Я никогда не смешиваю & и &&, или | и ||, поэтому я не решаюсь сделать это с помощью ^ и ^^.

Мне было бы удобнее писать собственную функцию bool XOR(bool,bool).

Ответ 1

Оператор != служит для этой цели для значений bool.

Ответ 2

Для истинной логической операции XOR это будет работать:

if(!A != !B) {
    // code here
}

Ответ 3

Правильная логическая реализация 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 != не имеет этого свойства.

Ответ 4

Есть другой способ сделать 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;
}

Ответ 5

Оператор XOR не может быть закорочен; т.е. вы не можете предсказать результат выражения XOR, просто оценив его левый операнд. Таким образом, нет причин для предоставления версии ^^.

Ответ 6

Был добавлен хороший код, который решил проблему лучше, чем! 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

Ответ 7

Используйте простой:

return ((op1 ? 1 : 0) ^ (op2 ? 1 : 0));

Ответ 8

Я использую "xor" (похоже, это ключевое слово; в Code::Blocks по крайней мере он становится полужирным), так же, как вы можете использовать "и" вместо && и "или" вместо ||.

if (first xor second)...

Да, это поразрядно. К сожалению.

Ответ 9

Вот как я думаю, вы пишете сравнение 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);

Ответ 10

#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 (длина отличается!)