Reputation: 12784
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
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
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
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
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
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
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
Reputation: 141
One more for C++03:
for(bool a = false, b = true; b; a = !a, b = a)
Use b.
Upvotes: 2
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
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