Is there an equivalent to the “for … else” Python

2019-03-09 03:38发布

Python has an interesting for statement which lets you specify an else clause.

In a construct like this one:

for i in foo:
  if bar(i):
    break
else:
  baz()

the else clause is executed after the for, but only if the for terminates normally (not by a break).

I wondered if there was an equivalent in C++? Can I use for ... else?

12条回答
三岁会撩人
2楼-- · 2019-03-09 04:03

Something like:

auto it = foo.begin(), end = foo.end();
while ( it != end && ! bar( *it ) ) {
    ++ it;
}
if ( it != foo.end() ) {
    baz();
}

should do the trick, and it avoids the unstructured break.

查看更多
爷的心禁止访问
3楼-- · 2019-03-09 04:05

A simpler way to express your actual logic is with std::none_of:

if (std::none_of(std::begin(foo), std::end(foo), bar))
    baz();

If the range proposal for C++17 gets accepted, hopefully this will simplify to:

if (std::none_of(foo, bar)) baz();
查看更多
爱情/是我丢掉的垃圾
4楼-- · 2019-03-09 04:05

You could use a lambda function for this:

[&](){
  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();
}();

This should behave exactly like Python's "for..else", and it has some advantages over the other solutions:

  • It's a true drop-in replacement for "for..else": the "for" section can have side effects (unlike none_of, whose predicate must not modify its argument), and it has access to the outer scope.
  • It's more readable than defining a special macro.
  • It doesn't require any special flag variables.

But... I'd use the clunky flag variable, myself.

查看更多
Root(大扎)
5楼-- · 2019-03-09 04:07

It's not only possible in C++, it's possible in C. I'll stick with C++ to make the code comprehensible though:

for (i=foo.first(); i != NULL || (baz(),0); i = i.next())
{
    if bar(i):
        break;
}

I doubt I'd let that through a code review, but it works and it's efficient. To my mind it's also clearer than some of the other suggestions.

查看更多
放荡不羁爱自由
6楼-- · 2019-03-09 04:08

If doesn't mind using goto also can be done in following way. This one saves from extra if check and higher scope variable declaration.

for(int i = 0; i < foo; i++)
     if(bar(i))
         goto m_label;
baz();

m_label:
...
查看更多
闹够了就滚
7楼-- · 2019-03-09 04:13

Yes you can achieve the same effect by:

auto it = std::begin(foo);
for (; it != std::end(foo); ++it)
     if(bar(*it))
         break;
if(it == std::end(foo))
    baz();
查看更多
登录 后发表回答