Как написать цикл for для значений bool (false и true) - PullRequest
46 голосов
/ 10 января 2012

Вопрос в основном для развлечения / любопытства: как написать цикл for в C ++, который бы повторял два значения 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 и цикл заканчивается.

После некоторого размышления, я считаю, что это невозможно сделать в C ++ 03 без второй переменной илиоснованная на указателе конструкция, подобная предложенной Дитмаром Кюлем.Условие должно быть проверено три раза в желаемом исполнении, поэтому двух значений bool просто недостаточно.И цикл do-while работает, потому что первая итерация выполняется безоговорочно, условие проверяется только дважды, поэтому можно использовать значение bool для выбора между продолжением и выходом.

Ответы [ 8 ]

58 голосов
/ 10 января 2012

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


Вот версия C ++ 03:

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

(используйте либо aили b.)

7 голосов
/ 10 января 2012

При ограничении C ++ 2003 вы можете использовать подход, примерно эквивалентный подходу C ++ 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);
}
5 голосов
/ 24 мая 2014
for (int a = 0; a <= 1; a++)
  doStuff(a ? true : false);

И забудьте об ограничении «нет переходов в другие типы» :) В конце концов, ясность важнее, чем искусственные ограничения. Через пять лет вы будете читать свой собственный код и удивляться: «Какого черта я думал, это что-то вроде соревнования по запутыванию?»

4 голосов
/ 11 августа 2014
a = true;
do {
  use(a);
  a = !a;
} while (!a);

ОК, так что это не цикл для , но я бы сказал, что он более читабелен, чем любое из предложений цикла for (кроме подхода C ++ 11, конечно.)

2 голосов
/ 30 декабря 2016

Этот ответ обращается к «невозможному» C ++ 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;
    }
}

Это, безусловно, кажется как неопределенное поведение. C ++ 03 немного неясно, . Однако sizeof всегда должно быть как минимум 1 (с нестандартным исключением для массивов var-len 0-длины). Более того, поскольку нам гарантировано, что каждый символ не менее 8 бит, мы можем использовать второй для нашего счетчика.

Действительно, чтобы сделать это, нам нужно либо обойти детерминизм (не без отказа от гарантии, что мы итерируем по false, true ровно один раз), либо нашу ограничивающую систему типов.

2 голосов
/ 27 апреля 2012

Еще один для C ++ 03:

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

Используйте b.

1 голос
/ 10 января 2012

Это тоже работает:

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

(вроде перевернутого решения, чем у @ KerrekSB)

0 голосов
/ 20 декабря 2017

Я знаю, что вы просили решение без преобразования в другой тип, но я полагаю, что вы имеете в виду "без преобразования в не присвоенный другой тип"Вот ответ, предлагающий объект, заменяющий 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);
...