web-dev-qa-db-fra.com

Comment écrire une boucle `for` sur des valeurs bool (false et true)

Une question principalement pour le plaisir/la curiosité: comment écrire une boucle for en C++ qui itérerait sur deux valeurs de bool (c'est-à-dire true et false), en utilisant uniquement les opérations avec bool (c'est-à-dire sans conversions à d'autres types)?

L’arrière-plan est que je voulais vérifier le nombre de solutions possibles pour une équation telle que (A && B) || (!B && !C && !D) == true et commencer à écrire quelque chose comme for (bool A=false; ??? ; ++A) for (bool B=false; ...) etc. mais me suis immédiatement retrouvé coincé par ??? - c’est-à-dire quelle serait la condition pour continuer la boucle? Bien sûr, je l'ai réécrit pour utiliser int, et je sais aussi qu'une boucle do ... while fonctionnera, mais je me demandais s'il était jamais possible d'écrire une telle boucle for? Et comme SO ne semble pas avoir de réponse, j'ai décidé de demander :)


Mise à jour: notez qu'une variante "évidente" for(bool A=false; !A; A=true) suggérée dans au moins deux réponses maintenant supprimées ne s'exécutera qu'une seule fois, car pour la seconde, la condition !A devient false et la boucle se termine.

Après quelques réflexions, je pense qu'il est impossible de le faire en C++ 03 sans une seconde variable ou une construction basée sur un pointeur, comme suggéré par Dietmar Kühl. La condition doit être testée trois fois dans l'exécution souhaitée. Deux valeurs d'une valeur booléenne ne suffisent donc pas. Et la boucle do-while fonctionne parce que la première itération est exécutée de manière inconditionnelle, la condition n'est vérifiée que deux fois. Une valeur bool peut donc être utilisée pour choisir entre continuer et quitter.

44
Alexey Kukanov

En C++ 11: for (bool b : { false, true }) { /* ... */ }


Voici une version C++ 03:

for (bool a = true, b = false; b != a; a = a && b, b = !b) { /*...*/ }

(Utilisez a ou b.)

55
Kerrek SB

Lorsque vous êtes limité à C++ 2003, vous pouvez utiliser une approche à peu près équivalente à celle de C++ 2011;

{
  bool const bools[] = { false, true };
  for (bool const* it(bools); it != std::end(bools); ++it) {
      bool a(*it);
      use(a);
  }
}

Peut-être emballé dans une macro. Vous pouvez aussi utiliser

for (bool a: { false, true }) {
    use(a);
}
7
Dietmar Kühl
for (int a = 0; a <= 1; a++)
  doStuff(a ? true : false);

Et oubliez la restriction "pas de conversions vers d'autres types" :) En fin de compte, la clarté est plus importante que les restrictions artificielles. Dans cinq ans, vous lirez votre propre code et vous vous demanderez "à quoi diable étais-je en train de penser, s'agit-il d'une sorte de concours d'obfuscation?"

5
Andrei Pokrovsky
a = true;
do {
  use(a);
  a = !a;
} while (!a);

OK, ce n’est donc pas une boucle pour , mais j’arguerais que c’est plus lisible que toutes les suggestions de boucles for (autres que l’approche C++ 11, bien sûr).

4
mdk

Un de plus pour C++ 03:

for(bool a = false, b = true; b; a = !a, b = a)  

Utilisez b.

2
Aotium

Celui-ci fonctionne aussi:

for (bool a = false, b = false; a == b; b = !b, a = a || b) { }

(sorte de solution inversée que celle de @ KerrekSB)

1
jrok

Je sais que vous avez demandé une solution sans conversion en un autre type, mais je suppose que vous voulez dire "sans conversion en un autre type non approprié". Voici une réponse proposant un objet remplaçant bool dans ce cas particulier.

struct IterableBool
{
  bool b;
  bool out_of_scope;
  IterableBool() : b(false), out_of_scope(false) {}
  IterableBool(bool b_) : b(b_), out_of_scope(false) {}
  IterableBool(IterableBool ib) : b(ib.b), out_of_scope(ib.out_of_scope) {}
  operator bool () { return this->b; }
  bool in_scope() const { return !this->out_of_scope; }
  IterableBool& operator ++ ()
  {                    
    this->out_of_scope = this->b;
    this->b = true;
    return *this;
  }
  IterableBool operator ++ (int)
  {
    IterableBool copy = *this;
    ++(*this);
    return copy;
  }
  IterableBool& operator -- ()
  {
    this->out_of_scope = !this->b;
    this->b = false;
    return *this;
  }
  IterableBool operator -- (int)
  {
    IterableBool copy = *this;
    --(*this);
    return copy;
  }
};

// Usage :
for(IterableBool ib = false;  ib.in_scope(); ++ib)
  do_stuff((bool)ib);
0
Caduchon