Is there an equivalent to the "for ... else" Python loop in C++?

26,464

Solution 1

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();

Solution 2

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:
...

Solution 3

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();

Solution 4

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.

Solution 5

This is my rough implementation in C++:

bool other = true;
for (int i = 0; i > foo; i++) {
     if (bar[i] == 7) {
          other = false;
          break;
     }
} if(other)
     baz();
Share:
26,464
Delgan
Author by

Delgan

It's me.

Updated on October 11, 2020

Comments

  • Delgan
    Delgan over 3 years

    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?

  • Admin
    Admin almost 10 years
    Note that this counts up from 0 to foo while the Python loop goes through the elements of the iterable foo. Probably easy to adjust though (compare to end()).
  • Admin
    Admin almost 10 years
    No. The Python loop doesn't count at all. i probably never is an integer. It's more like C++11 for (auto i : foo).
  • m.wasowski
    m.wasowski almost 10 years
    for(auto it = begin(something); it != end(something); ++i) ... if (it == end(something))`... Also please remember, that everytime you do postfix incrementation unecessary, a kitten dies.
  • Easton
    Easton almost 10 years
    Whoops, fixed the issue.
  • Admin
    Admin almost 10 years
    The break is fine IMHO, and in any case that change is completely orthogonal to the actual meat (it != foo.end()).
  • Thijs van Dien
    Thijs van Dien almost 10 years
    +1 because I think this solution most clearly states the intent.
  • ifyalciner
    ifyalciner almost 10 years
    @MatthiasB As far as I understand question is not about what to use, instead it is about the possible implementations in C++.
  • ifyalciner
    ifyalciner almost 10 years
    @MatthiasB And also I don't think that 'goto' is outdated. Because there are still fields where you need to omit extra 'if' checks and declarations for performance and memory considerations, while still programming in C++.
  • Jarod42
    Jarod42 almost 10 years
    You may add your own exception, else you badly catch exception from bar(i) and baz()
  • ifyalciner
    ifyalciner almost 10 years
    @Jarod42 you are right. Custom exception would be better.
  • ifyalciner
    ifyalciner almost 10 years
    @MatthiasB I think this will be a good example. Actual impact of the thread actually about emptying pipeline because of the false prediction in the case. But still a branch can effect terribly. Especially if you are repeating many times which i don't see reason the neglect many repetitions because domain is absent. Also I use C++ in embedded systems. You are right that it is not a good practice but still i believe is a good exception.
  • Admin
    Admin almost 10 years
    @Faruxx I'm afraid you'll have to elaborate. There is not a single mention of "goto" in that question, and the subject matter (branch prediction) doesn't lend itself to any obvious examples. The issue is an unpredictable jump in the machine code, a goto also produces jump instructions and does not alter predictability.
  • ifyalciner
    ifyalciner almost 10 years
    @delnan Sorry I couldn't be clear. My point was that by using goto you can eliminate a branch. And in the link if you check the answers will see that one solution to branch prediction is removing the branch altogether. But still I see no more necessity of the arguing on the matter. Thanks for all responses.
  • Admin
    Admin almost 10 years
    @Faruxx A goto is a branch (possibly an unconditional one). The only instance of removing branches code I could find in the answers doesn't use goto. If you want to argue that goto allows replacing conditional branches with unconditional ones, please give an example because so far it sounds like cargo cult.
  • ifyalciner
    ifyalciner almost 10 years
    @delnan in the most voted answer; here : int t = (data[c] - 128) >> 31; sum += ~t & data[c];. Of course goto is a branch such as break. I have removed second branch which is a conditional one that you can see in other answers.
  • Admin
    Admin almost 10 years
    @Faruxx Okay, missed that one, but it doesn't need or use goto either. I'm aware of branch prediction and its effects and no not dispute them. What I'm asking is how goto helps avoid branch mispredictions.
  • ifyalciner
    ifyalciner almost 10 years
    @delnan No no! I never meant that. It helps only to remove branch removal where theoretically you are removing branch correct or mis prediction. The reason i have given that example is this code block may repeat many times, one more if check will increase the chance of branch mis-prediction (as well as correct prediction). In some cases where code optimization is important goto is still a good practice for experienced ones. @MatthiasB is right where you are coding for an user application in big project with many people that understandably of code is more important than optimization.
  • James Kanze
    James Kanze almost 10 years
    @BenVoigt Good point. That's what comes of typing too quickly. Should be a while; I'll fix it.
  • Joeytje50
    Joeytje50 over 9 years
    @m.wasowski could you please explain why i++ would be so bad in a forloop? It's got exactly the same functionality as ++i there. I personally think i++ looks better, because it's got the part that changes the variable after the variable name itself, just like where +=1 comes after i in the normal i+=1, etc. In cases where it doesn't matter to the outcome of the code, I always use i++.
  • m.wasowski
    m.wasowski over 9 years
    @Joeytje50 i++ can be significantly slower, as it involves creating a new object; it is a bad habit to use it and you won't find it in decent code in place where ++i can be used instead. Personally, it forces me unecessarilly to slow down and think if there is was a reason to use it, or is it just sloppy code. Even if for a second, it might be annoying.
  • Joeytje50
    Joeytje50 over 9 years
    @m.wasowski this guy's tests say otherwise. I get why i++ could be slower in some situations, but in a forloop it makes no difference if you've got a modern enough compiler (which is what I'm taking from that SO link), so I would still prefer i++ because of those things I said. So, to fix your original statement: "Everytime you do postfix incrementation unnecessarily, your compiler turns it into exactly the same as prefix incrementation."
  • m.wasowski
    m.wasowski over 9 years
    @Joeytje50 mind that this is answer for a different programming language. For example, iterators are not primitive types like int. Also see comments below, you will find all the reasons why ++i should be used as default. And IMHO, for sake of consistency, the same should be used for primitive types, like int.
  • Андрей Беньковский
    Андрей Беньковский over 8 years
    You don't need a semicolon after the label. The context implies there are operators after this code (otherwise one could just use an early return).
  • Андрей Беньковский
    Андрей Беньковский over 8 years
    The goto part isn't that bad. That's what I'd use in this situation. I think it is actually more readable than the flag-based solution.
  • Андрей Беньковский
    Андрей Беньковский over 8 years
    Sacrificing readability to save 5 seconds of typing is usually a very bad idea.
  • srdjan.veljkovic
    srdjan.veljkovic over 8 years
    Well, readability is subjective, while typing isn't. It's a trade-off, like everything else. I'm not advocating its use, just showing how you can achieve a "for each...else" in C++ without goto (which has its own problems).
  • ifyalciner
    ifyalciner over 8 years
    @АндрейБеньковский Thanks for suggestions and mentioning.
  • 0kcats
    0kcats over 8 years
    A goto pattern here is much, much better than declaring a macro.
  • 0kcats
    0kcats over 8 years
    If we consider language equivalency, then this is the only valid answer. Python does not have gotos, while C++ has, and all other examples, such as using return, a temporary variable and break, or exceptions can be done with Python. Plus, this case (for else) as well as breaking out of a nested loop are probably the two only cases of valid applications of goto in C++.
  • kamikaze
    kamikaze over 8 years
    goto is well defined and often the most comprehensible (i.e. best maintainable) solution for complex loop handling. This solution has my vote (I would have given a similar one).
  • 0kcats
    0kcats over 8 years
    Not completely equivalent. For example, it does not allow modification of the elements of the container by the "bar". Not to mention, that it made me (a C++ dev) go look it up in the help, while the the original OP python sample I had no problem understanding immediately. The stl turns into a mud pile.
  • 0kcats
    0kcats over 8 years
    I was referring to the help page here: cplusplus.com/reference/algorithm/none_of or here en.cppreference.com/w/cpp/algorithm/all_any_none_of. Both say that the predicate shall not modify the argument.
  • Tony Delroy
    Tony Delroy over 8 years
    @0kcats: hmmm... 25.1/8 does say "The function object pred shall not apply any non-constant function through the dereferenced iterator.", so you're right. Interesting! Related discussion here. Cheers
  • Андрей Беньковский
    Андрей Беньковский over 8 years
    The first example can be replaced with an if statement using python's built-ins any and map or an iterator comprehension.
  • Tony Delroy
    Tony Delroy over 8 years
    @agomcas: this is very interesting, as is the contrast with equivalent C++, e.g.: for (int retrynum = 0; ; ++retrynum) { try { attempt_operation(); } catch (const SomeException&) { if (retrynum == max_retries) throw ...; } }. Not sure which I prefer.
  • agomcas
    agomcas over 8 years
    @АндрейБеньковский but I believe with the any() construction there is not way to recover which element fulfilled the condition. In the for...else case you have it stored in item and may do something else with it.
  • Андрей Беньковский
    Андрей Беньковский over 8 years
    @agomcas I continued my experiments. link. I'm not sure which of two solutions is more readable.
  • Андрей Беньковский
    Андрей Беньковский over 8 years
    @agomcas A bit more improved version: melpon.org/wandbox/permlink/xiQBiPYY9zBV0ceY
  • agomcas
    agomcas over 8 years
    @АндрейБеньковский For me, readability of the for... else is better by far. The other option involves creation of a separate sentinel object + using the generator returned from filter + using next with a default return (first time I ever encountered this usage BTW). It goes from a construction that you can explain in an introduction to programming right just after 'if...else' and 'for' to a construction that needs quite some knowledge of python (plus I bet is more expensive in resources), just to match the same amount of lines. Not really a contender?
  • Tony Delroy
    Tony Delroy over 8 years
    @agmos: "with the any() construction there is not way to recover which element fulfilled the condition" - that's part of the self-documenting beauty of it - the code reader knows up front that it doesn't matter which element matches whenever any is used, while find_if implies it may matter. Good programmers will pick accordingly.
  • ferdynator
    ferdynator over 8 years
    Why i > foo? Shouldn't it be i < foo?
  • Yam Marcovic
    Yam Marcovic about 8 years
    Why would it require specifying the type?
  • arekolek
    arekolek about 8 years
    @YamMarcovic Admittedly, I wasn't aware you can use auto specifier in lambdas. But it works only in C++14 and I was using C++11.
  • nonsensickle
    nonsensickle over 7 years
    I'm not sure how I feel about the macro leaving behind a new variable in my scope. In your example an iterator x will be left behind after the else statement. There isn't a nice way to get around this one...
  • srdjan.veljkovic
    srdjan.veljkovic over 7 years
    I added an example of a way to avoid bringing a new variable into current scope. I'm not saying it's nice, but, it works. :)
  • Matej Kolec'ko
    Matej Kolec'ko over 4 years
    I think using goto is antipattern nowadays, but if you do it on this micro place I think you are okay, but I think this should be last thing to consider to use.
  • 12431234123412341234123
    12431234123412341234123 almost 3 years
    @MatthiasB Can you explain which construct he uses that you think is outdated?
  • 12431234123412341234123
    12431234123412341234123 almost 3 years
    @MatthiasB This answer is a prime example why goto isn't outdated in C.