【问题标题】:How to write a `for` loop over bool values (false and true)如何在布尔值(假和真)上编写“for”循环
【发布时间】:2012-01-10 14:48:53
【问题描述】:

一个主要是为了好玩/好奇的问题:如何在 C++ 中编写一个for 循环,该循环将迭代bool 的两个值(即truefalse),仅使用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 并且循环结束。

经过一番思考,我相信如果没有第二个变量或 Dietmar Kühl 建议的基于指针的构造,在 C++03 中是不可能做到的。该条件应在所需的执行中测试 3 次,因此两个布尔值是不够的。 do-while 循环之所以有效,是因为第一次迭代是无条件执行的,条件只检查了两次,因此可以使用 bool 值在继续和退出之间进行选择。

【问题讨论】:

  • 令人惊讶的是,错误答案被删除的速度如此之快!
  • 是的,你不讨厌他们这样做吗?我觉得这是个好问题。我投了赞成票。
  • 因为这个网站不是为了好玩/好奇。真正的问题! PS不,不是我,我也很好奇。
  • 为什么投反对票?这是一个合理的问题,也是一个有趣的古董。 +1

标签: c++ for-loop boolean


【解决方案1】:

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


这是一个 C++03 版本:

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

(使用ab。)

【讨论】:

  • 这是一个带有初始化列表的有趣版本。
【解决方案2】:

当仅限于 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);
}

【讨论】:

  • 我认为您可以将该数组打包到 for 循环的声明部分中。不过不确定。
  • @Wolf:回复写于 2012 年。我想,过去我并没有假设 C++11 普遍可用(尽管我发现了实现 std::end() -1998 的必要功能。跨度>
  • 太好了,你更新了它 :) 它将帮助我记住 std::end ;)
【解决方案3】:
for (int a = 0; a <= 1; a++)
  doStuff(a ? true : false);

忘记“不转换为其他类型”的限制 :) 归根结底,清晰比人为的限制更重要。五年后,您将阅读自己的代码并想知道“我到底在想什么,这是某种混淆竞赛吗?”

【讨论】:

  • 如果您使用 char/uint8_t 而不是 int,它们很有可能会编译成相同的底层数据类型,并为您提供零成本转换。
  • @SlippD.Thompson 这取决于doStuff int 是否有效。
  • 或者你可以 for (int a = 0; a
【解决方案4】:
a = true;
do {
  use(a);
  a = !a;
} while (!a);

好的,所以它不是 for 循环,但我认为它比任何 for 循环建议都更具可读性(当然,C++11 方法除外。)

【讨论】:

  • 要使continue 在循环内按预期工作:a = false; do { ... } while (a = !a);。变量/常量中的初始值:a = init; do { ... } while (init != (a = !a));
【解决方案5】:

C++03 的另一个:

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

使用 b。

【讨论】:

    【解决方案6】:

    这个答案解决了“不可能的”C++03,只有单变量的解决方案

    首先,让我们确认,对于两个输入true,false,没有任何确定性算术表达式仅依赖于单个输入变量都为真,但对于必须是truefalse 之一的第三个值则不是。

    但是,我们可以“作弊”。不过,我会恳求你证明我确实在作弊。

    #include <iostream>
    
    using namespace std;
    
    int main() {
        for (bool b = false; *((char*)&b) != 2; *((char*)&b) += 1) {
            cout << "bool " << b << endl;
        }
    }
    

    这确实似乎像未定义的行为。 C++03 有点unclear about it。但是,sizeof 必须始终至少为 1(0 长度 var-len 数组的非标准例外)。此外,由于我们保证每个字符至少为 8 位,因此我们可以使用第二个作为计数器。

    确实,要做到这一点,我们需要避开确定性(不能不放弃我们对 false, true 只进行一次迭代的保证)或我们的约束类型系统。

    【讨论】:

      【解决方案7】:

      这个也可以:

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

      (比@KerrekSB's 倒置的解决方案)

      【讨论】:

        【解决方案8】:

        我知道您要求解决方案而不转换为其他类型,但我想您的意思是“不转换为未分配的其他类型”。这是一个答案,在这种特定情况下提供了一个替换 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);
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-01-23
          • 2020-01-05
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-07-15
          • 1970-01-01
          • 2021-08-03
          相关资源
          最近更新 更多