Самый простой способ перевернуть логическое значение?

124

Я просто хочу перевернуть логическое значение на основе того, что уже есть. Если это правда - сделайте ложью. Если ложь - сделай правдой.

Вот отрывок из моего кода:

switch(wParam) {

case VK_F11:
  if (flipVal == true) {
     flipVal = false;
  } else {
    flipVal = true;
  }
break;

case VK_F12:
  if (otherVal == true) {
     otherValVal = false;
  } else {
    otherVal = true;
  }
break;

default:
break;
}
John T
источник

Ответы:

341

Вы можете перевернуть значение так:

myVal = !myVal;

поэтому ваш код сократится до:

switch(wParam) {
    case VK_F11:
    flipVal = !flipVal;
    break;

    case VK_F12:
    otherVal = !otherVal;
    break;

    default:
    break;
}
John T
источник
7
Это не только самый простой, но и самый чистый способ.
Sharptooth 04
два случая могут быть объединены, поскольку они делают одно и то же.
Дэвид Аллан Финч,
1
По умолчанию: break; действительно необходимо? Без него выключатель не закончится так же?
Крис Лутц,
12
По умолчанию: break; не нужно.
Роб К.
4
Если вы переключаете что-то длинное, например object1-> system1.system2.system3.parameter1, может быть полезно иметь макрос TOGGLE (a). Это предотвращает некоторые ошибки и делает все более читаемым на узких экранах.
OJW
77

Понятно нужен заводской выкрой!

KeyFactory keyFactory = new KeyFactory();
KeyObj keyObj = keyFactory.getKeyObj(wParam);
keyObj.doStuff();


class VK_F11 extends KeyObj {
   boolean val;
   public void doStuff() {
      val = !val;
   }
}

class VK_F12 extends KeyObj {
   boolean val;
   public void doStuff() {
      val = !val;
   }
}

class KeyFactory {
   public KeyObj getKeyObj(int param) {
      switch(param) {
         case VK_F11:
            return new VK_F11();
         case VK_F12:
            return new VK_F12();
      }
      throw new KeyNotFoundException("Key " + param + " was not found!");
   }
}

: D

</sarcasm>
Нарисовался
источник
9
Возможно, мы могли бы добавить шаблон singleton для фабрики.
Дрю
@Orm Потому что вы ORM ? :)
mlvljr
3
Обратите внимание на тонкую рекомендацию перейти на Java!
Механическая улитка
Что ж ... я думаю, нам нужен еще один крупный выпуск C ++ для этого, может быть C ++ / 51
0x6900
Привет ребят! Я думаю, что ваш подход не реентерабелен. Вам нужен как минимум atomic_bool, а лучше мьютекс или очередь событий. Кроме того, нам нужен шаблон-наблюдатель для отслеживания состояния val.
Марко Фройденбергер
38

Если вы знаете, что значения 0 или 1, вы можете это сделать flipval ^= 1.

Майк Данлэйви
источник
1
Зачем использовать побитовый оператор для логической операции? Мне кажется, что это бесполезная обфускация.
Марк Пим,
5
@Mark: извините. Думаю, я старомоден. Но это действительно помогает, если ваше выражение L-значения действительно длинное, поэтому вам не нужно его повторять. Кроме того, вы можете сказать flipval ^ = TRUE. Это лучше?
Майк Данлэйви, 04
6
@Alnitak: В некоторых обстоятельствах вы правы. Я видел, как некоторые люди собирают кусочки вместе, чтобы «сэкономить место», и действуют так, как будто инструкции для доступа к ним не занимают места.
Майк Данлэйви, 06
2
@Albert: ^это оператор исключающего ИЛИ . 0^1есть 1, и 1^1есть 0. Это то же самое, что и добавление, если вы игнорируете бит переноса. Или вы можете думать об этом так: если один из битов равен 1, результат обратен другому биту. Или вы можете думать об этом как о вопросе: эти две части разные?
Mike Dunlavey
1
@MikeDunlavey, если вы используете устройство с 4 МБ Flash для пространства кода и 3 КБ SRAM для пространства данных, то это оправданный способ действий!
MM
33

Самое простое решение, которое я нашел:

x ^= true;
Xamid
источник
11
x = !x;не только короче, но и разборчивее.
Родриго
13
Обратите внимание, что eg longVariableName ^= true;явно короче, чем longVariableName = !longVariableName;И каждый программист должен знать XOR.
xamid 05
a ^= bзначит a = a ^ b, где ^означает XOR. Обозначения a °= bдля a = a ° bлюбого оператора °очень распространены в синтаксисе C / C ++ / C #.
xamid 06
2
Анекдотично, но я недавно наткнулся на строку. gRackWidget->modules->first().lights[PATTERN1_LIGHT + i].value = !gRackWidget->modules->first().lights[PATTERN1_LIGHT + i].value;Конечно, самое чистое, что можно сделать, - это расширить ее до нескольких строк и использовать временные переменные для хранения объектов, но gRackWidget->modules->first().lights[PATTERN1_LIGHT + i].value ^= 1она гораздо более читабельна, менее подвержена ошибкам и меньше символов, чем исходный код. ,
Vortico
1
Кроме того, меньшее количество дублирования означает меньшую вероятность того, что вы забудете обновить ОБЕИХ стороны уравнения во время быстрых изменений в разработке / долгих дней / ночей кодирования.
Katastic Voyage
11

Просто для информации - если вместо целого числа ваше обязательное поле представляет собой один бит в более крупном типе, используйте вместо этого оператор 'xor':

int flags;

int flag_a = 0x01;
int flag_b = 0x02;
int flag_c = 0x04;

/* I want to flip 'flag_b' without touching 'flag_a' or 'flag_c' */
flags ^= flag_b;

/* I want to set 'flag_b' */
flags |= flag_b;

/* I want to clear (or 'reset') 'flag_b' */
flags &= ~flag_b;

/* I want to test 'flag_b' */
bool b_is_set = (flags & flag_b) != 0;
Альнитак
источник
9

Кажется, это все бесплатно ... Хех. Вот еще одна вариация, которая, я думаю, больше относится к категории «умных», чем то, что я бы рекомендовал для производственного кода:

flipVal ^= (wParam == VK_F11);
otherVal ^= (wParam == VK_F12);

Я думаю, это преимущества:

  • Очень кратко
  • Не требует ветвления

И столь же очевидный недостаток -

  • Очень кратко

Это похоже на решение @korona, использующее?:, Но на один (небольшой) шаг дальше.

размотать
источник
2
По порядку операций, я думаю, вы можете опустить круглые скобки для еще большей краткости. : O
Дрю
8

Просто потому, что в списке нет моего любимого способа переключения bool ...

bool x = true;
x = x == false;

тоже работает. :)

(да, x = !x;это понятнее и легче читается)

Rozwel
источник
6

Решение codegolf'ish было бы больше похоже:

flipVal = (wParam == VK_F11) ? !flipVal : flipVal;
otherVal = (wParam == VK_F12) ? !otherVal : otherVal;
Korona
источник
2

Я предпочитаю решение Джона Т, но если вы хотите использовать весь код, ваше утверждение логически сводится к следующему:

//if key is down, toggle the boolean, else leave it alone.
flipVal = ((wParam==VK_F11) && !flipVal) || (!(wParam==VK_F11) && flipVal);
if(wParam==VK_F11) Break;

//if key is down, toggle the boolean, else leave it alone.
otherVal = ((wParam==VK_F12) && !otherVal) || (!(wParam==VK_F12) && otherVal);
if(wParam==VK_F12) Break;
JosephStyons
источник
Разве вам не нужно проверять wParam на VK_F11 и VK_F12?
drby 04
2
flipVal ^= 1;

то же самое касается

otherVal
evandrix
источник
0

Очевидно, вам нужно гибкое решение, которое может поддерживать типы, маскирующиеся под логические. Это позволяет:

template<typename T>    bool Flip(const T& t);

Затем вы можете специализировать это для разных типов, которые могут претендовать на логические значения. Например:

template<>  bool Flip<bool>(const bool& b)  { return !b; }
template<>  bool Flip<int>(const int& i)    { return !(i == 0); }

Пример использования этой конструкции:

if(Flip(false))  { printf("flipped false\n"); }
if(!Flip(true))  { printf("flipped true\n"); }

if(Flip(0))  { printf("flipped 0\n"); }
if(!Flip(1)) { printf("flipped 1\n"); }

Нет, я не серьезно.

ДМА
источник
0

Для целых чисел со значениями 0 и 1 вы можете попробовать:

value = abs(value - 1);

MWE в C:

#include <stdio.h>
#include <stdlib.h>
int main()
{
        printf("Hello, World!\n");
        int value = 0;
        int i;
        for (i=0; i<10; i++)
        {
                value = abs(value -1);
                printf("%d\n", value);
        }
        return 0;
}
Артур
источник
0

Просто потому, что мне нравится подвергать сомнению код. Я предлагаю вам также использовать тернар, сделав что-то вроде этого:

Пример:

bool flipValue = false;
bool bShouldFlip = true;
flipValue = bShouldFlip ? !flipValue : flipValue;
Джон Блэк
источник