如何在布尔值(假和真)上编写“for”循环

Posted

技术标签:

【中文标题】如何在布尔值(假和真)上编写“for”循环【英文标题】:How to write a `for` loop over bool values (false and true) 【发布时间】: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 【参考方案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);

【讨论】:

以上是关于如何在布尔值(假和真)上编写“for”循环的主要内容,如果未能解决你的问题,请参考以下文章

明晰C语言中的真/假和0/1

Spark UDF:如何在每一行上编写一个 UDF 以提取嵌套结构中的特定值?

c++如何定义布尔型数组使其初始值为true?

如何在 Pandas DataFrame 上编写条件数组操作

字符转详细与初步了解for循环

来自 True 值范围(开始和结束)的布尔列表,不使用 for 循环