> Starting in C++17, a[b] always evaluates a before evaluating b.
Okay, I'll bite. Why did C++17 specify this?
Okay, I'll bite. Why did C++17 specify this?
The example
a[b]
doesn't really exhibit the unexpected, but as I understand it f()->a[b()]
could evaluate as temp = b()
f()->a[temp]
which it seems reasonable to consider unexpected. The lack of left to right sequencing here seems not-dissimilar to the lack of sequencing in call arguments, which was also realized to be a needless footgun and fixed.And yes, it does seem that there were a lot more people hell bent on resisting correcting unnecessary UB in the past than today, but they’re still around.
if (map.contains(foo)) {
bob(map[foo]);
}
over the (vastly uglier) more efficient: if (auto it = map.find(foo); it != map.end()) {
bob(*it);
}
Of course languages like C# manage this in a more elegant way with out parameters declarable at the call site. if let Some(x) = map.get(foo) {
bob(x)
}
One subtle but noteworthy thing is that the idiom only mentions map by name once, which is nice if you have a very long map name, and prevents copy paste bugs where you only update one of the two mentions. for (x <- map.get(foo)) {
bob(x)
}
// or
map.get(foo).foreach(bob)
// or
map.get(foo) match {
case Some(x) => bob(x)
} std::map::find (item) != map.end() <=> std::map::contain (item) foo()[bar()];
In nearly all cases it won't matter, but it can matter if foo() and bar() have some kind of shared state (or affect each other's return values, but seriously don't do that). In general it's better to have a defined evaluation order unless there's some compelling reason not to.That is not the stance C++ has taken in the past, so the question of why they changed it is still unanswered.
a.f(foo(1)).g(foo(2)).arr[foo(3)].h(foo(4));
In C++14, the foo() calls happened in unspecified order.
C++17 guarantees that "a(b)" and "a[b]" evaluate "a" first, which effectively means the foo() calls will now happen in order (1 to 4).