Is the following code safe? Particularly, if vec
is an rvalue reference, does the last line do what it should (namely a recursion in which the elements of vec
are correctly summed up)?
template<typename VectorType>
auto recurse(VectorType&& vec, int i)
{
if(i<0)
return decltype(vec[i])();
return vec[i] + recurse(std::forward<VectorType>(vec), i-1); //is this line safe?
}
My doubts are related to the fact that since the order of evaluation is unspecified, the vector could have been moved before operator[]
is evaluated, and therefore the latter could fail.
Is this fear justified, or is there some rule that prevents this?
Consider the following:
Even after all 3 calls to
recurse
in the example above, thethings
vector would still be intact.If the recursion were changed to:
the results would then be undefined, as either
vec[i]
or--i
could be evaluated in either order.Function calls are like sequence points: The results of argument expressions must be computed before the function is called. The order in which this happens, however, is undefined -- even with respect to sub-expressions within the same statement.
Forcing the construction of an intermediate within the recursion statement would also result in undefined behavior.
For example:
Here,
vec[i]
orActualType{forward<VectorType>(vec)}
could be evaluated in either order. The latter would either copy-construct or move-construct a new instance ofActualType
, which is why this is undefined.In Summary
Yes, your example will sum the contents of the vector.
There is no reason for the compiler to construct an intermediate, so successive invocations of
recurse
each receive an indirect reference to the same, unchanging instance.Addendum
As pointed out in a comment, it is possible for a non-const
operator[]
to mutate the instance ofVectorType
, whatever that might be. In this case, the result of the recursion would be undefined.