c++rvaluelvalue

Why does passing rvalue to lvalue reference work in this case?


I was doing Leetcode when I stumbled upon this interesting technique. Here it is in short:

#include <iostream>
#include <vector>

void print(std::vector<int>& vec)
{
    for (int i : vec)
    {
        std::cout << i << ", ";
    }
}

int main()
{
    print(std::vector<int>(5) = {1,2,3,4,5});

    return 0;
}

We are passing seemingly rvalue to an lvalue reference, which is usually illegal, but in this specific case, it works somehow. Is there any explanation or maybe I'm missing something?


Solution

  • operator= of std::vector returns an lvalue reference and is callable on rvalue as well as lvalue object expressions (because it is just a normal non-static member function without ref-qualifier).

    So std::vector<int>(5) = {1,2,3,4,5} is permitted and is an lvalue expression that can be bound by the lvalue reference in the parameter.

    Of course, that's terrible style. print should just have a const lvalue reference parameter and then

    print({1,2,3,4,5});
    

    would simply work.

    And even if one really wants to pass a rvalue to a non-const lvalue reference, it would be better to use a function specifically for that which clearly communicates the intent, e.g.:

    template<typename T>
    T& as_lvalue(T&& t) { return static_cast<T&>(t); }
    
    //...
    
    print(as_lvalue(std::vector<int>{1,2,3,4,5}));