Let's imagine we have a struct for holding 3 doubles with some member functions:
struct Vector {
double x, y, z;
// ...
Vector &negate() {
x = -x; y = -y; z = -z;
return *this;
}
Vector &normalize() {
double s = 1./sqrt(x*x+y*y+z*z);
x *= s; y *= s; z *= s;
return *this;
}
// ...
};
This is a little contrived for simplicity, but I'm sure you agree that similar code is out there. The methods allow you to conveniently chain, for example:
Vector v = ...;
v.normalize().negate();
Or even:
Vector v = Vector{1., 2., 3.}.normalize().negate();
Now if we provided begin() and end() functions, we could use our Vector in a new-style for loop, say to loop over the 3 coordinates x, y, and z (you can no doubt construct more "useful" examples by replacing Vector with e.g. String):
Vector v = ...;
for (double x : v) { ... }
We can even do:
Vector v = ...;
for (double x : v.normalize().negate()) { ... }
and also:
for (double x : Vector{1., 2., 3.}) { ... }
However, the following (it seems to me) is broken:
for (double x : Vector{1., 2., 3.}.normalize()) { ... }
While it seems like a logical combination of the previous two usages, I think this last usage creates a dangling reference while the previous two are completely fine.
- Is this correct and Widely appreciated?
- Which part of the above is the "bad" part, that should be avoided?
- Would the language be improved by changing the definition of the range-based for loop such that temporaries constructed in the for-expression exist for the duration of the loop?