In GitHub repositories there are not few examples where the range-expression in range-based for loop is surrounded in std::move
, e.g. in pytorch:
...
outputs = (*call_op)(schema, std::move(inputs), std::move(outputs));
for (auto&& output : std::move(outputs)) {
torch::jit::push(*stack, std::move(output));
}
Since output
here just iterates over the elements of std::move(outputs)
and we have std::move(output)
inside loop body, does for-loop is really different from the variant without the first std::move
:
for (auto&& output : outputs) {
torch::jit::push(*stack, std::move(output));
}
and if yes, can the difference be observed with some classes from the standard library or only with some specially designed ones?
The range-based for
statement is defined by translation:
{
init-statement_opt
auto &&range = for-range-initializer ;
auto begin = begin-expr ;
auto end = end-expr ;
for ( ; begin != end; ++begin ) {
for-range-declaration = * begin ;
statement
}
}
where begin-expr
and end-expr
either are range.begin()
and range.end()
, or are begin(range)
and end(range)
, dependent on whether lookup for the former succeeds.
This means that within begin-expr
and end-expr
, range
is an lvalue, regardless of whether for-range-initializer
is an lvalue or an xvalue (or even a prvalue).
So wrapping a for-range-initializer
in std::move()
will not have any effect on program behavior.