Ответ 1
В С++ 11: for (bool b : { false, true }) { /* ... */ }
Здесь версия С++ 03:
for (bool a = true, b = false; b != a; a = a && b, b = !b) { /*...*/ }
(Используйте либо a
, либо b
.)
Вопрос в основном для удовольствия/любопытства: как написать цикл for
в С++, который будет перебирать два значения a bool
(т.е. true
и false
), используя только операции с bool
(т.е. без преобразования в другие типы)?
Фон состоит в том, что я хотел проверить, сколько решений существует для уравнения типа (A && B) || (!B && !C && !D) == true
, и начал писать что-то вроде for (bool A=false; ??? ; ++A) for (bool B=false; ...)
и т.д., но сразу же застрял в ???
- то есть, что было бы условием продолжения петля? Конечно, я переписал его для использования int, и я также знаю, что цикл do ... while
будет работать, но мне стало любопытно, можно ли написать такой цикл for
? И поскольку SO, похоже, не имеет ответа, я решил спросить:)
Обновление: обратите внимание, что "очевидный" вариант for(bool A=false; !A; A=true)
, предложенный, по крайней мере, в двух теперь удаленных ответах, будет запускать только одну итерацию, потому что для второго условие !A
становится false
, и цикл завершается.
После некоторого размышления я считаю невозможным сделать это в С++ 03 без второй переменной или конструкцией, основанной на указателях, как предложено Dietmar Kühl. Условие должно быть проверено три раза в желаемом исполнении, поэтому двух значений bool просто недостаточно. И цикл do-while работает, потому что первая итерация выполняется безоговорочно, условие проверяется только дважды, поэтому значение bool можно использовать для выбора между продолжением и выходом.
В С++ 11: for (bool b : { false, true }) { /* ... */ }
Здесь версия С++ 03:
for (bool a = true, b = false; b != a; a = a && b, b = !b) { /*...*/ }
(Используйте либо a
, либо b
.)
При ограничении на С++ 2003 вы можете использовать подход, который примерно эквивалентен подходу С++ 2011;
{
bool const bools[] = { false, true };
for (bool const* it(bools); it != std::end(bools); ++it) {
bool a(*it);
use(a);
}
}
Возможно, он упакован в макрос. Вы также можете использовать
for (bool a: { false, true }) {
use(a);
}
for (int a = 0; a <= 1; a++)
doStuff(a ? true : false);
И забудьте о ограничениях "без конверсий на другие типы":) В конце дня ясность важнее искусственных ограничений. Через пять лет вы будете читать свой собственный код и задаваться вопросом: "Какого черта я думал, это какой-то конкурс по обфускации?"
a = true;
do {
use(a);
a = !a;
} while (!a);
ОК, так что это не цикл for, но я бы сказал, что он более читабельен, чем любой из предложений for loop (за исключением подхода С++ 11, конечно.)
Еще один для С++ 03:
for(bool a = false, b = true; b; a = !a, b = a)
Используйте b.
В этом ответе рассматривается "невозможное" решение С++ 03, единственная переменная
Во-первых, давайте вернемся к тому, что ни одно детерминированное арифметическое выражение, основанное только на одной входной переменной, не может быть истинно для обоих входов true,false
, но не для третьего значения, которое должно быть одним из true
или false
.
Однако мы можем "обмануть". Хотя, я умоляю вас доказать, что я на самом деле обманываю.
#include <iostream>
using namespace std;
int main() {
for (bool b = false; *((char*)&b) != 2; *((char*)&b) += 1) {
cout << "bool " << b << endl;
}
}
Это, безусловно, похоже на поведение undefined. С++ 03 немного неясно об этом. Однако sizeof
всегда должно быть не менее 1 (с нестандартным исключением для массивов var-len длиной 0 строк). Более того, поскольку мы гарантируем, что каждый char имеет не менее 8 бит, мы можем использовать второй для нашего счетчика.
В самом деле, для этого нам нужно либо ограничить детерминизм (не может, не отказываясь от гарантии, которую мы итерируем по false, true
ровно один раз), или нашей сдерживающей системы типов.
Это тоже работает:
for (bool a = false, b = false; a == b; b = !b, a = a || b) { }
(вид инвертированного решения, чем @KerrekSB)
Я знаю, что вы попросили решение без конвертации в другой тип, но я полагаю, вы имеете в виду "без преобразования в нераспределенный другой тип". Вот ответ, предлагающий объект, заменяющий bool
в этом конкретном случае.
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);