Il modo più semplice per capovolgere un valore booleano?


124

Voglio solo capovolgere un booleano in base a ciò che è già. Se è vero, rendilo falso. Se è falso, rendilo vero.

Ecco il mio estratto di codice:

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;
}

Risposte:


341

Puoi capovolgere un valore in questo modo:

myVal = !myVal;

quindi il tuo codice si ridurrebbe a:

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

    case VK_F12:
    otherVal = !otherVal;
    break;

    default:
    break;
}

7
Non solo questo è il modo più semplice, ma anche il più pulito.
punta di diamante il

i due casi possono essere uniti mentre fanno la stessa cosa.
David Allan Finch

1
È predefinito: break; davvero necessario? L'interruttore non finirà allo stesso modo senza di esso?
Chris Lutz

12
Default: pausa; non è necessario.
Rob K

4
Se stai attivando qualcosa di prolisso come object1-> system1.system2.system3.parameter1, può essere utile avere una macro TOGGLE (a). Ciò previene alcuni errori e rende tutto più leggibile su schermi stretti.
GUW

77

Chiaramente hai bisogno di un modello di fabbrica!

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
Probabilmente potremmo aggiungere anche il pattern singleton per la factory.
Drew il

@Orm Perché sei un ORM ? :)
mlvljr

3
Nota la sottile raccomandazione di passare a Java!
Chiocciola meccanica

Bene ... penso che abbiamo bisogno di un'altra versione principale di C ++ per questo, potrebbe essere C ++ / 51
0x6900

Hey ragazzi! Penso che il tuo approccio non sia rientrante. Hai bisogno almeno di atomic_bool, meglio un mutex o una coda di eventi. Inoltre, abbiamo bisogno di un modello di osservazione per monitorare lo stato di val.
Marco Freudenberger

38

Se sai che i valori sono 0 o 1, potresti farlo flipval ^= 1.


1
Perché utilizzare un operatore bit per bit per un'operazione logica? Odora di offuscamento inutile per me.
Mark Pim

5
@Mark: Scusa. Immagino di essere all'antica. Ma aiuta se la tua espressione del valore L è molto lunga, quindi non devi ripeterla. Inoltre, potresti dire flipval ^ = TRUE. Va meglio?
Mike Dunlavey

6
@ Alnitak: hai ragione in alcune circostanze. Ho visto alcune persone mettere insieme dei bit per "risparmiare spazio" e agire come se le istruzioni per accedervi non occupassero spazio.
Mike Dunlavey

2
@Albert: ^è l' operatore esclusivo o . 0^1è 1, ed 1^1è 0. È lo stesso che aggiungere se ignori il bit di trasporto. Oppure puoi pensare ad esso come se uno dei due bit è 1, il risultato è l'inverso dell'altro bit. Oppure puoi pensare che si ponga la domanda: questi due bit sono diversi?
Mike Dunlavey

1
@MikeDunlavey se sei su un dispositivo con 4M di Flash per lo spazio del codice e 3K di SRAM per lo spazio dei dati, allora questo è un modo giustificato di agire!
MM

33

La soluzione più semplice che ho trovato:

x ^= true;

11
x = !x;non è solo più breve, ma anche più leggibile.
Rodrigo

13
Nota che ad esempio longVariableName ^= true;è chiaramente più breve di longVariableName = !longVariableName;E ogni programmatore dovrebbe conoscere XOR.
xamid

a ^= bsignifica a = a ^ b, dove ^significa XOR. La notazione a °= bper a = a ° bqualsiasi operatore °è molto comune nella sintassi C / C ++ / C #.
xamid

2
Aneddotico, ma di recente mi sono imbattuto nella riga gRackWidget->modules->first().lights[PATTERN1_LIGHT + i].value = !gRackWidget->modules->first().lights[PATTERN1_LIGHT + i].value;Ovviamente, la cosa più pulita da fare è espanderla su più righe e utilizzare variabili temporanee per memorizzare gli oggetti, ma gRackWidget->modules->first().lights[PATTERN1_LIGHT + i].value ^= 1è molto più leggibile, meno soggetta a errori e meno caratteri rispetto al codice originale .
Vortico

1
Inoltre, una minore duplicazione significa meno possibilità di dimenticare di aggiornare ENTRAMBI i lati dell'equazione durante rapidi cambiamenti di sviluppo / lunghi giorni / notti di codifica.
Viaggio Katastico

11

Solo per informazione: se invece di un numero intero il tuo campo richiesto è un singolo bit all'interno di un tipo più grande, usa invece l'operatore "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

Questo sembra essere un libero per tutti ... Eh. Ecco un'altra variante, che immagino sia più nella categoria "intelligente" di qualcosa che consiglierei per il codice di produzione:

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

Immagino che i suoi vantaggi siano:

  • Molto conciso
  • Non richiede ramificazione

E uno svantaggio altrettanto ovvio è

  • Molto conciso

Questo è vicino alla soluzione di @ korona usando?: Ma ha fatto un (piccolo) passo avanti.


2
In ordine di operazioni, penso che tu possa omettere la parentesi per essere ancora più conciso. : O
Drew

8

Solo perché il mio modo strano preferito per attivare o disattivare un bool non è elencato ...

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

funziona anche. :)

(sì, x = !x;è più chiaro e più facile da leggere)


6

La soluzione codegolf'ish sarebbe più simile a:

flipVal = (wParam == VK_F11) ? !flipVal : flipVal;
otherVal = (wParam == VK_F12) ? !otherVal : otherVal;

2

Preferisco la soluzione di John T, ma se vuoi andare tutto in codice, la tua dichiarazione si riduce logicamente a questo:

//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;

Non devi controllare wParam con VK_F11 e VK_F12?
drby


0

Chiaramente hai bisogno di una soluzione flessibile in grado di supportare tipi mascherati da booleani. Quanto segue lo consente:

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

Puoi quindi specializzarlo per diversi tipi che potrebbero fingere di essere booleani. Per esempio:

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

Un esempio di utilizzo di questo costrutto:

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"); }

No, non dico sul serio.


0

Per i numeri interi con valori di 0 e 1 puoi provare:

value = abs(value - 1);

MWE in 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

Solo perché mi piace mettere in discussione il codice. Propongo che tu possa utilizzare anche il ternario facendo qualcosa del genere:

Esempio:

bool flipValue = false;
bool bShouldFlip = true;
flipValue = bShouldFlip ? !flipValue : flipValue;
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.