如何在布尔值(假和真)上编写“for”循环
Posted
技术标签:
【中文标题】如何在布尔值(假和真)上编写“for”循环【英文标题】:How to write a `for` loop over bool values (false and true) 【发布时间】:2012-01-10 14:48:53 【问题描述】:一个主要是为了好玩/好奇的问题:如何在 C++ 中编写一个for
循环,该循环将迭代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
并且循环结束。
经过一番思考,我相信如果没有第二个变量或 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) /*...*/
(使用a
或b
。)
【讨论】:
这是一个带有初始化列表的有趣版本。【参考方案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
,没有任何确定性算术表达式仅依赖于单个输入变量都为真,但对于必须是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 有点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”循环的主要内容,如果未能解决你的问题,请参考以下文章
Spark UDF:如何在每一行上编写一个 UDF 以提取嵌套结构中的特定值?