Search code examples
c++rvalue-referencelvaluerange-based-loop

C++ Does Ranged-Based For Loop Use RValue Reference?


Hi I have a quick question - over here it says ranged-based for loops of the form

for ( init-statement (optional) range-declaration : range-expression )

are equivalent to the code:

{
    auto && __range = range-expression ;
    for (auto __begin = begin-expr, __end = end-expr; __begin != __end; ++__begin)
    {
        range-declaration = *__begin;
        loop-statement
    }
}

So if you do

std::vector<datatype> vector1;
for (auto& datatype : vector1)

it's perfectly acceptable. However if you do

std::vector<datatype>&& vector2 = vector1;
or
std::vector<datatype>&& vector2(vector1);

it doesn't compile. As far as I know you cannot initialize an rvalue reference with an lvalue like vector1. What exactly is going on here and what is the difference between the ranged-based for loop's underlying code and the assignment/construct statements? Thanks!


Solution

  • As you observed, std::vector<datatype>&& is indeed an rvalue reference, and it cannot be bind to an lvalue like vector1.

    However, in this statement:

    auto && __range = range-expression;
    

    __range is not an rvalue reference.

    It is in fact a Forwarding reference and can therefore bind to either rvalue or lvalue.

    The key difference is the usage of auto in the latter case. It makes it equivalent to T && x where T is a template parameter, as in the following example from the documentation above:

    template<class T>
    int f(T&& x)                      // x is a forwarding reference
    {
        return g(std::forward<T>(x)); // and so can be forwarded
    }
    

    A side note:
    Forwarding reference are related to the issue of perfect forwarding. See more about it here.