Alexey Kukanov
Alexey Kukanov

Reputation: 12784

How to write a `for` loop over bool values (false and true)

A question mostly for fun/curiosity: how to write a for loop in C++ that would iterate over two values of a bool (i.e. true and false), using only operations with bool (i.e. without conversions to other types)?

The background is that I wanted to check how many solutions exists for an equation like (A && B) || (!B && !C && !D) == true, and started to write something like for (bool A=false; ??? ; ++A) for (bool B=false; ...) etc but immediately got stuck by ??? - i.e. what would be the condition to continue the loop? Of course I rewrote it to use int, and I also know that a do ... while loop will work, but I got curious if it's ever possible to write such a for loop? And since SO does not seem to have an answer, I decided to ask :)


Update: note that an "obvious" variant for(bool A=false; !A; A=true) suggested in at least two now-removed answers will only run one iteration, because for the second one the condition !A becomes false and the loop ends.

After some pondering, I believe it's impossible to do it in C++03 without a second variable or a pointer based construct like suggested by Dietmar Kühl. The condition should be tested three times in a desired execution, so two values of a bool are simply not enough. And the do-while loop works because the first iteration is executed unconditionally, the condition is only checked twice and so a bool value can be used to select between continuing and exiting.

Upvotes: 60

Views: 33071

Answers (9)

CodeLurker
CodeLurker

Reputation: 1371

A possibly less confusing version for old school programmers, based on Pokrovsky's answer:

bool firstPass=true;
for (int i = 0; i < 2; i++, firstPass=false)
    myfunc(firstPass);

or more simply:

for (int pass = 1; i < 3; i++)
    myfunc(pass == 1);

or even

for (int secondPass = 0; secondPass < 2; ++secondPass)
    myfunc(!secondPass);

(which Pokrovsky's answer optimizes to).

I think it's important for the variable to make sense when a programmer sees it down in the loop.

Upvotes: 0

Caduchon
Caduchon

Reputation: 5231

I know you asked for a solution without conversion to other type, but I suppose you mean "without conversion to unappropriated other type". Here is an answer offering an object replacing bool in this specific case.

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

Upvotes: 0

Dietmar K&#252;hl
Dietmar K&#252;hl

Reputation: 154025

When restricted to C++2003 you could use an approach roughly equivalent to the C++2011 approach;

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

Possibly packed up in a macro. You can also use

for (bool a: { false, true }) {
    use(a);
}

Upvotes: 8

VF1
VF1

Reputation: 1652

This answer addresses the "impossible" C++03, single-variable only solution

First, let us confirm that no deterministic arithmetic expression relying only on a single input variable can be true for both inputs true,false but then not for a third value that must be one of true or false.

However, we can "cheat". Though, I'd implore you to prove I'm actually cheating.

#include <iostream>

using namespace std;

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

This certainly seems like undefined behavior. C++03 is a bit unclear about it. However, sizeof must always be at least 1 (with a non-standard exception for 0-length var-len arrays). Moreover, since we're guaranteed each char is at least 8 bits, we can use the second one for our counter.

Indeed, to do this we need to either skirt determinism (can't without giving up the guarantee we iterate over false, true exactly once) or our constraining type system.

Upvotes: 2

mdk
mdk

Reputation: 51

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

OK, so it's not a for loop, but I would argue it is more readable than any of the for loop suggestions (other than the C++11 approach, of course.)

Upvotes: 5

Andrei Pokrovsky
Andrei Pokrovsky

Reputation: 3846

for (int a = 0; a <= 1; a++)
  doStuff(a ? true : false);

And forget about "no conversions to other types" restriction :) In the end of the day clarity is more important than artificial restrictions. Five years down the line you'll be reading your own code and wondering "what the heck was I thinking, is this some sort of an obfuscation contest?"

Upvotes: 5

Aotium
Aotium

Reputation: 141

One more for C++03:

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

Use b.

Upvotes: 2

jrok
jrok

Reputation: 55425

This one works, too:

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

(sort of inverted solution than @KerrekSB's)

Upvotes: 1

Kerrek SB
Kerrek SB

Reputation: 477514

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


Here's a C++03 version:

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

(Use either a or b.)

Upvotes: 73

Related Questions