是否有等效于C++中的"for ... else" Python循环?
Is there an equivalent to the "for ... else" Python loop in C++?
Python有一个有趣的for
语句,它允许你指定一个else
子句。
在这样的结构中:
for i in foo:
if bar(i):
break
else:
baz()
else
子句在for
之后执行,但前提是for
正常终止(而不是break
)。
我想知道在c++中是否有一个等效的?我可以使用for ... else
吗?
如果不介意使用goto
也可以按以下方式完成。这可以避免额外的if
检查和更高的作用域变量声明。
for(int i = 0; i < foo; i++)
if(bar(i))
goto m_label;
baz();
m_label:
...
表达实际逻辑的更简单方法是使用std::none_of
:
if (std::none_of(std::begin(foo), std::end(foo), bar))
baz();
如果c++ 17的范围建议被接受,希望这将简化为:
if (std::none_of(foo, bar)) baz();
这是我在c++中的粗略实现:
bool other = true;
for (int i = 0; i > foo; i++) {
if (bar[i] == 7) {
other = false;
break;
}
} if(other)
baz();
是的,你可以达到同样的效果:
auto it = std::begin(foo);
for (; it != std::end(foo); ++it)
if(bar(*it))
break;
if(it == std::end(foo))
baz();
您可以使用lambda函数:
[&](){
for (auto i : foo) {
if (bar(i)) {
// early return, to skip the "else:" section.
return;
}
}
// foo is exhausted, with no item satisfying bar(). i.e., "else:"
baz();
}();
这应该完全像Python的"for.. "Else",它比其他解决方案有一些优势:
- 这是一个真正的替代"for.."else": "for"部分可能有副作用(不像none_of,它的谓词不能修改它的参数),而且它可以访问外部作用域。 这比定义一个特殊的宏更具可读性。
- 不需要任何特殊的标志变量
但是…我自己也会使用笨拙的flag变量。
我不知道在C/c++中有什么优雅的方法来完成这个(不涉及标志变量)。建议的其他选项比这可怕得多……
为了回答@Kerrek SB关于现实生活中的用法,我在我的代码中找到了一些(简化的片段)
示例1:典型的find/fail
for item in elements:
if condition(item):
do_stuff(item)
break
else: #for else
raise Exception("No valid item in elements")
示例2:限制尝试次数
for retrynum in range(max_retries):
try:
attempt_operation()
except SomeException:
continue
else:
break
else: #for else
raise Exception("Operation failed {} times".format(max_retries))
类似于
auto it = foo.begin(), end = foo.end();
while ( it != end && ! bar( *it ) ) {
++ it;
}
if ( it != foo.end() ) {
baz();
}
应该可以做到这一点,并且它避免了非结构化的break
。
这不仅在c++中是可能的,在C中也是可能的。我将坚持使用c++,使代码易于理解:
for (i=foo.first(); i != NULL || (baz(),0); i = i.next())
{
if bar(i):
break;
}
我怀疑我是否会让它通过代码审查,但它是有效的,而且是有效的。在我看来,这也比其他一些建议更清晰。
在c++中没有这样的语言结构,但是,由于预处理器的"魔力",您可以为自己创建一个。例如,像这样的代码(c++ 11):
#include <vector>
#include <iostream>
using namespace std;
#define FOR_EACH(e, c, b) auto e = c.begin(); for (; e != c.end(); ++e) {b} if (e == c.end()) {}
int main()
{
vector<int> v;
v.push_back(1);
v.push_back(2);
FOR_EACH(x, v, {
if (*x == 2) {
break;
}
cout << "x = " << *x << " ";
})
else {
cout << "else";
}
return 0;
}
这应该输出x = 1 else
。
如果将if (*x == 2) {
更改为if (*x == 3) {
,则输出结果应为x = 1 x = 2
。
如果你不喜欢在当前作用域中添加一个变量,你可以稍微改变它:
#define FOR_EACH(e, c, b, otherwise) {auto e = c.begin(); for (; e != c.end(); ++e) {b} if (e == c.end()) {} otherwise }
则使用:
FOR_EACH(x, v, {
if (*x == 2) {
break;
}
cout << "x = " << *x << " ";
},
else {
cout << "else";
})
当然,并不完美,但是,如果小心使用,将节省您的打字量,如果大量使用,将成为项目"词汇表"的一部分。
可能不存在适合所有问题的单一解决方案。在我的例子中,一个标志变量和一个带有auto
说明符的基于范围的for
循环效果最好。下面是问题代码的等效代码:
bool none = true;
for (auto i : foo) {
if (bar(i)) {
none = false;
break;
}
}
if (none) baz();
与使用迭代器相比,输入更少。特别是,如果使用for
循环初始化变量,可以使用它来代替布尔标志。
由于auto
类型,如果你想内联条件而不是调用bar()
(如果你不使用c++ 14),它比std::none_of
更好。
我遇到了一种情况,两种情况都发生了,代码看起来像这样:
for (auto l1 : leaves) {
for (auto x : vertices) {
int l2 = -1, y;
for (auto e : support_edges[x]) {
if (e.first != l1 && e.second != l1 && e.second != x) {
std::tie(l2, y) = e;
break;
}
}
if (l2 == -1) continue;
// Do stuff using vertices l1, l2, x and y
}
}
这里不需要迭代器,因为v
指示break
是否发生。
使用std::none_of
需要在lambda表达式的参数中显式指定support_edges[x]
元素的类型。
直接回答:不,你可能不能,或者它是基于编译器的。但这里有一个hack的宏,这种工作!
注意事项:
我通常用Qt编程,所以我习惯了有一个foreach循环,从来没有直接处理迭代器。
我用Qt的编译器(v 5.4.2)测试了这个,但它应该工作。这是恶心的原因有几个,但通常是你想要的。我不能容忍这样的编码,但是只要你注意语法,它没有理由不能工作。
#include <iostream>
#include <vector>
#define for_else(x, y) __broke__ = false; for(x){y} if (__broke__) {}
#define __break__ __broke__ = true; break
bool __broke__; // A global... wah wah.
class Bacon {
public:
Bacon(bool eggs);
inline bool Eggs() {return eggs_;}
private:
bool eggs_;
};
Bacon::Bacon(bool eggs) {
eggs_ = eggs;
}
bool bar(Bacon *bacon) {
return bacon->Eggs();
}
void baz() {
std::cout << "called bazn";
}
int main()
{
std::vector<Bacon *>bacons;
bacons.push_back(new Bacon(false));
bacons.push_back(new Bacon(false));
bacons.push_back(new Bacon(false));
for_else (uint i = 0; i < bacons.size(); i++,
std::cout << bacons.at(i)->Eggs();
if (bar(bacons.at(i))) {
__break__;
}
) else {
baz();
}
bacons.push_back(new Bacon(true));
bacons.push_back(new Bacon(false));
for_else (uint i = 0; i < bacons.size(); i++,
std::cout << bacons.at(i)->Eggs();
if (bar(bacons.at(i))) {
__break__;
}
) else {
baz();
}
return EXIT_SUCCESS;
}
你可以像在Python中一样通过定义两个宏来使用for-else:
#define BREAK {CONTINUETOELSE = false; break;}
#define FORWITHELSE(x, y) {bool CONTINUETOELSE = true; x if(!CONTINUETOELSE){} y}
现在将for
和else
放入FORWITHELSE
宏中,用逗号分隔,并使用BREAK
代替break
。下面是一个例子:
FORWITHELSE(
for(int i = 0; i < foo; i++){
if(bar(i)){
BREAK;
}
},
else{
baz();
}
)
有两件事你需要记住:在else
之前放一个逗号,用BREAK
代替break
。
我来这里是因为我有同样的问题,虽然在C。我得到的最好的东西是
bool notTerminated = true;
for (int i = 0; i < 50 || (notTerminated = false); i++)
if (bar(i))
break;
if (! notTerminated)
baz();
解释:(notTerminated = false)
是一个赋值函数,它总是返回false值,它永远不会影响条件,如果条件为真,它将被计算。
我将使用一个简单的辅助变量来完成这个任务:
#include <stdio.h>
#include <stdbool.h>
int main()
{
bool b;
printf("Numbers which are multiples of 7:n");
for (int i=8; b=(i<12); i++)
{
if (i%7==0)
{
printf("%d", i);
break;
}
}
if (!b)
{
printf("no numbers foundn");
}
return 0;
}
这样,您只需要在一个地方实现条件(在上面的示例中为i<12
)。
- "error: no matching function for call to"构造函数错误
- 表示"accepting anything for this template argument" C++概念的通配符
- 如何在C++中从两个单独的for循环中添加两个数组
- 在Linux for Windows上编译C++代码时出错
- 调用专用模板时出错"no matching function for call to [...]"
- 我的简单if-else语句是如何无法访问的代码
- 为什么我的for循环不能正确获取argv
- 为什么我不能在 FOR LOOP 中使用 i/10,C++?
- Arduino:for/while/if在void setup()或void loop()之前?——错误:之前需要不合格
- 线程,如果else语句,都是错误的上下文切换后,会发生什么
- 试图避免在 for 循环中出现 if-else 语句,但代码似乎有一些错误
- C++ 使用 OpenMP 时,如果 for 循环在 if else 语句中出错
- 如何退出 for 循环内的嵌套 if-else 语句?(C/C++)
- 优化代码/实现"for"循环而不是长"if - else if - else"
- 如何仅使用if-else语句(no-for、do/while等)使此代码循环一定次数?(c++)
- 在c++中编写for/else的简明方法
- 是否有等效于C++中的"for ... else" Python循环?
- for 循环的问题,它同时读取 if 和 else if 语句
- 为什么我在 for 循环中收到'Else without previous if'错误?
- 为什么 for 循环总是在 else 语句处停止