Python has an interesting for
statement which lets you specify an else
clause.
In a construct like this one:
for i in foo:
if
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.
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;
}
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.
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".
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:
...
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();