it-swarm.com.de

Wie schreibt man eine for-Schleife über bool-Werte (false und true)

Eine Frage hauptsächlich aus Spaß/Neugier: Wie schreibt man eine for-Schleife in C++, die zwei Werte einer bool durchlaufen würde (d. H. true und false), wobei nur Operationen mit bool (d. H. Ohne Konvertierungen zu anderen Typen) verwendet werden?

Der Hintergrund ist, dass ich überprüfen wollte, wie viele Lösungen für eine Gleichung wie (A && B) || (!B && !C && !D) == true vorhanden sind, und anfing, etwas wie for (bool A=false; ??? ; ++A) for (bool B=false; ...) etc zu schreiben, aber sofort von ??? hängengeblieben war - d. H. Was wäre die Bedingung, um die Schleife fortzusetzen? Natürlich habe ich es für die Verwendung von int neu geschrieben, und ich weiß auch, dass eine do ... while-Schleife funktionieren wird, aber ich wurde neugierig, ob es überhaupt möglich ist, eine solche for-Schleife zu schreiben. Und da SO keine Antwort zu haben scheint, entschied ich mich zu fragen :)


Update: Beachten Sie, dass eine "offensichtliche" Variante for(bool A=false; !A; A=true), die in mindestens zwei jetzt entfernten Antworten vorgeschlagen wird, nur eine Iteration ausführt, da für die zweite !A die Bedingung false wird und die Schleife endet.

Nach einigem Nachdenken glaube ich, dass es unmöglich ist, dies in C++ 03 ohne eine zweite Variable oder ein Zeiger-basiertes Konstrukt, wie von Dietmar Kühl vorgeschlagen, durchzuführen. Die Bedingung sollte dreimal in einer gewünschten Ausführung getestet werden, sodass zwei Werte eines Bool einfach nicht ausreichen. Und die Do-while-Schleife funktioniert, weil die erste Iteration unbedingt ausgeführt wird. Die Bedingung wird nur zweimal geprüft, und es kann ein Bool-Wert verwendet werden, um zwischen dem Fortfahren und dem Beenden zu wählen.

44
Alexey Kukanov

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


Hier ist eine C++ 03-Version:

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

(Verwenden Sie entweder a oder b.)

55
Kerrek SB

Bei einer Beschränkung auf C++ 2003 können Sie einen Ansatz verwenden, der ungefähr dem C++ 2011-Ansatz entspricht.

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

Möglicherweise in einem Makro verpackt. Sie können auch verwenden

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

Und vergessen Sie die Einschränkung "keine Umstellung auf andere Typen" :) Am Ende des Tages ist Klarheit wichtiger als künstliche Einschränkungen. Nach fünf Jahren werden Sie Ihren eigenen Code lesen und sich fragen, "Was zum Teufel habe ich gedacht? Ist das eine Art Verschleierungswettbewerb?"

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

OK, es ist also keine for - Schleife, aber ich würde behaupten, dass es besser lesbar ist als alle for-Schleifen-Vorschläge (abgesehen von C++ 11 natürlich).

4
mdk

Noch eine für C++ 03:

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

Verwenden Sie b.

2
Aotium

Diese Antwort adressiert die "unmögliche" C++ 03-Lösung mit einer einzigen Variablen

Lassen Sie uns zunächst bestätigen, dass kein deterministischer arithmetischer Ausdruck, der sich nur auf eine einzige Eingabevariable stützt, für beide Eingaben true,false wahr sein darf, jedoch nicht für einen dritten Wert, der true oder false sein muss.

Wir können jedoch "betrügen". Allerdings würde ich Sie bitten, zu beweisen, dass ich tatsächlich betrüge.

#include <iostream>

using namespace std;

int main() {
    for (bool b = false; *((char*)&b) != 2; *((char*)&b) += 1) {
        cout << "bool " << b << endl;
    }
}

Dies ist sicherlich scheint und undefiniertes Verhalten. C++ 03 ist ein bisschen unklar darüber . sizeof muss jedoch immer mindestens 1 sein (mit einer nicht standardmäßigen Ausnahme für var-len-Arrays mit 0-Länge). Da uns garantiert wird, dass jedes Zeichen mindestens 8 Bit umfasst, können wir das zweite für unseren Zähler verwenden.

Um dies zu tun, müssen wir entweder den Determinismus umrunden (kann nicht ohne die Garantie aufzugeben, dass wir false, true genau einmal durchlaufen) oder unser einschränkendes Typensystem.

2
VF1

Dieses funktioniert auch:

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

(eine Art invertierte Lösung als @ KerrekSBs)

1
jrok

Ich weiß, dass Sie nach einer Lösung ohne Konvertierung in einen anderen Typ gefragt haben, aber Sie meinen "ohne Konvertierung in einen anderen Typ". Hier ist eine Antwort, die ein Objekt anbietet, das in diesem speziellen Fall bool ersetzt.

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