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

15

85

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?

Enoch answered 11/7, 2014 at 8:50 Comment(11)
It's an interesting idea that comes up every now and then. Out of curiosity, how often is such a construction used in real code?Walls
@KerrekSB This is the real question. When I started learning Python I kind of found this to be trivial and confusing to beginners at best; I couldn't find any pressing requirement for this construct.Inexecution
I know it's a real question, but it's not real code -it's just too and bar. I'm wondering how often real algorithms need an explicit extra branch that only applies when the loop completes. I can't think of useful examples right now.Walls
@KerrekSB implementing find() is a classic example where this conctruct is used.Voiceless
@m.wasowski: really? Usually the standard early return works just fine for find-like algorithms, with no need for a separate "loop complete" block.Walls
@Kerrek: Usually the early return really is a return, not a break, and then it does skip the code immediately following the loop.Malchy
I do like this construction, and I made a search to see If I could find some use cases of it in my code to answer @KerrekSB , but i need to post it as a answer because comments are not enoughShannonshanny
@agomcas: I have since been convinced that this construction is useful. The reasoning is this: All three of if (c), while (c) and for (...; c; ...) evaluate c, but at present only the first one lets you access the result of this expression. The other two are throwing away this information, which violates the principle that you should not throw away results that were obtained as part of a computation.Walls
However, I would have liked it much more if the keywords would have been other than 'else'. Something like 'nobreak' or even 'felse' and 'welse' that makes the intention stand out more than the plain else. Every time I use it I feel the need to add a comment #for else in that line, just in case.Shannonshanny
@agomcas: not break statement-block has the benefit of using existing keywords, for better backwards compatibility (and being strongly indicative of the conditions under which it runs). In C++ the use of else for this would conflict with existing code a la if (...) for (...) ...; else ....Matriarchy
Most of the time, when I encounter this need, I extract a method and replace break by return.Occasion
M
41

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();
Matriarchy answered 11/7, 2014 at 9:38 Comment(4)
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.Lithea
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.Lithea
@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. CheersMatriarchy
Then maybe std::cbegin() should express the intent better. Though I don't know why standard not just making std::none_of accepts const iterator in this case..Overstride
H
45

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:
...
Hoffert answered 11/7, 2014 at 9:12 Comment(19)
@MatthiasB As far as I understand question is not about what to use, instead it is about the possible implementations in C++.Hoffert
@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++.Hoffert
You may add your own exception, else you badly catch exception from bar(i) and baz()Soosoochow
@Soosoochow you are right. Custom exception would be better.Hoffert
@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.Hoffert
@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.Michalemichalski
@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.Hoffert
@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.Michalemichalski
@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.Hoffert
@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.Michalemichalski
@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.Hoffert
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).Cinchonize
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.Cinchonize
@АндрейБеньковский Thanks for suggestions and mentioning.Hoffert
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++.Lithea
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).Stillmann
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.Livre
@MatthiasB Can you explain which construct he uses that you think is outdated?Insectarium
@MatthiasB This answer is a prime example why goto isn't outdated in C.Insectarium
M
41

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();
Matriarchy answered 11/7, 2014 at 9:38 Comment(4)
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.Lithea
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.Lithea
@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. CheersMatriarchy
Then maybe std::cbegin() should express the intent better. Though I don't know why standard not just making std::none_of accepts const iterator in this case..Overstride
D
18

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();
Daedalus answered 11/7, 2014 at 8:57 Comment(3)
Whoops, fixed the issue.Daedalus
+1 because I think this solution most clearly states the intent.Aerography
Why i > foo? Shouldn't it be i < foo?Shulock
S
15

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();
Slickenside answered 11/7, 2014 at 8:58 Comment(7)
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()).Michalemichalski
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).Michalemichalski
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.Voiceless
@Voiceless 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++.Ostrander
@Ostrander 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.Voiceless
@Voiceless 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."Ostrander
@Ostrander 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.Voiceless
A
14

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.

Adipose answered 9/1, 2016 at 2:59 Comment(0)
S
4

I am not aware of an elegant way to accomplish this in C/C++ (not involving a flag variable). The suggested other options are much more horrible than that...

To answer @Kerrek SB about real life usages, I found a few in my code (simplified snippets)

Example 1: typical find/fail

for item in elements:
    if condition(item):
        do_stuff(item)
        break
else: #for else
    raise Exception("No valid item in elements")

Example 2: limited number of attempts

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))
Shannonshanny answered 16/12, 2015 at 6:52 Comment(7)
The first example can be replaced with an if statement using python's built-ins any and map or an iterator comprehension.Cinchonize
@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.Matriarchy
@АндрейБеньковский 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.Shannonshanny
@Shannonshanny I continued my experiments. link. I'm not sure which of two solutions is more readable.Cinchonize
@Shannonshanny A bit more improved version: melpon.org/wandbox/permlink/xiQBiPYY9zBV0ceYCinchonize
@АндрейБеньковский 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?Shannonshanny
@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.Matriarchy
R
3

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.

Russell answered 11/7, 2014 at 9:7 Comment(2)
The break is fine IMHO, and in any case that change is completely orthogonal to the actual meat (it != foo.end()).Michalemichalski
@BenVoigt Good point. That's what comes of typing too quickly. Should be a while; I'll fix it.Russell
A
3

There is no such language construct in C++, but, thanks to the "magic" of the preprocessor, you can make one for yourself. For example, something like this (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;
}

This should output x = 1 else.

If you change if (*x == 2) { to if (*x == 3) {, the output should be x = 1 x = 2.

If you don't like the fact that a variable is added in the current scope, you can change it slightly:

#define FOR_EACH(e, c, b, otherwise) {auto e = c.begin(); for (; e != c.end(); ++e) {b} if (e == c.end()) {} otherwise }

then use would be:

FOR_EACH(x, v, {
    if (*x == 2) {
        break;
    }        
    cout << "x = " << *x << " ";
},
else {
    cout << "else";
})

It's not perfect, of course, but, if used with care, will save you some amount of typing and, if used a lot, would become a part of the project's "vocabulary".

Analgesia answered 11/12, 2015 at 14:45 Comment(5)
Sacrificing readability to save 5 seconds of typing is usually a very bad idea.Cinchonize
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).Analgesia
A goto pattern here is much, much better than declaring a macro.Lithea
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...Kicker
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. :)Analgesia
G
2

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.

Gipsy answered 8/2, 2017 at 10:24 Comment(0)
C
0

There probably isn't a single solution that fits best all problems. In my case a flag variable and a range-based for loop with an auto specifier worked best. Here's an equivalent of the code in question:

bool none = true;
for (auto i : foo) {
  if (bar(i)) {
    none = false;
    break;
  }
}
if (none) baz();

It is less typing than using iterators. Especially, if you use the for loop to initialize a variable, you may use that instead of the boolean flag.

Thanks to auto typing it is better than std::none_of, if you want to inline the condition rather than call bar() (and if you are not using C++14).

I had a situation where both conditions occurred, the code looked something like this:

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
  }
}

No need for iterators here, because v indicates whether break occurred.

Using std::none_of would require specifying the type of support_edges[x] elements explicitly in arguments of a lambda expression.

Chlori answered 7/2, 2016 at 15:40 Comment(2)
Why would it require specifying the type?Biped
@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.Chlori
P
0

Direct answer: no, you probably can't, or it is compiler-based, at best. BUT here's a hack of a macro that kind of works!

A few notes:

I usually program with Qt, so I'm used to having a foreach loop, and never have to deal with iterators directly.

I tested this with Qt's compiler (v 5.4.2) but it should work. This is gross for several reasons, but generally does what you'd want. I don't condone coding like this, but there's no reason it shouldn't work as long as you're careful with the syntax.

#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 baz\n";
}

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;
}
Praline answered 31/5, 2017 at 21:10 Comment(0)
M
0

You can use for-else almost like in Python by defining two macros:

#define BREAK {CONTINUETOELSE = false; break;}
#define FORWITHELSE(x, y) {bool CONTINUETOELSE = true; x if(!CONTINUETOELSE){} y}

Now you put the for and the else inside the FORWITHELSE macro separated by a comma and use BREAK instead of break. Here is an example:

FORWITHELSE(
    for(int i = 0; i < foo; i++){
        if(bar(i)){
            BREAK;
        }
    },
    else{
        baz();
    }
)

There are two things you need to remember: to put a comma before the else and to use BREAK instead of break.

Mats answered 11/6, 2017 at 9:24 Comment(0)
D
0

I came here because I had the same question, in C though. The best thing I came out with is

bool notTerminated = true;
for (int i = 0; i < 50 || (notTerminated = false); i++)
    if (bar(i))
        break;
if (! notTerminated)
    baz();

Explanation: the (notTerminated = false) is an assignment that will always return the false value, it will never affect the condition and will be evaluated iif the condition if true.

Dorset answered 28/3, 2019 at 10:48 Comment(0)
A
0

If you don't mind inverting the logic, you can use else for:

std::vector<int> values = { 1, 2, 3 };

if (values.empty()) {
    puts("Vector was empty");
}
else for (auto&& v : values) {
    printf("%d, ", v);
}
Apul answered 4/1, 2024 at 2:36 Comment(0)
W
-1

I would accomplish this with a simple helper variable:

#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 found\n");
    }
    return 0;
}

This way, you need to implement the condition (in the above examplei<12) only at one place.

Wentz answered 10/10, 2019 at 19:7 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.