Search code examples
c++c++11autoperfect-forwardingtype-deduction

What's the difference between "auto v = f()" and "auto&& v = f()"?


#include <vector>

using namespace std;

vector<int> f()
{
    return{};
}

// Update: Below is not compilable
void g(vector<int>)
{}

// Update: Below is the my initial intent.
/*
void g(const vector<int>&)
{}
*/

void g(vector<int>&&)
{}

int main()
{
    auto       v1 = f();
    auto&& v2 = f();

    g(forward<vector<int>>(v1));
    g(forward<vector<int>>(v2));
}

Does C++11 guarantee g(forward<vector<int>>(v1)) will call f(vector<int>) or f(const vector<int>&) and g(forward<vector<int>>(v2)) will call f(vector<int>&&)?


Solution

  • The difference is that v1 is a vector while v2 is an rvalue reference to a vector.

    Overloading g the way you have done is a very bad idea. If the argument is a cv-unqualified rvalue, then the call will be ambiguous since both g's can accept the rvalue with the identity conversion sequence. It is, however, acceptable to have one overload take T& and the other take T&&.

    If you want to forward the value category of f(), don't copy/move it as you have done into v1. That destroys the value category information. v1 will always be an lvalue.

    Besides, you are not using std::forward properly. Both v1 and v2 will be cast to rvalue reference, and would behave the same way under overload resolution in that case.

    Here is what the proper usage of std::forward looks like:

    void g(vector<int>&);
    void g(vector<int>&&);
    int main() {
        auto&& v1 = function_returning_lvalue_vector();
        auto&& v2 = function_returning_rvalue_vector();
        g(forward<decltype(v1)>(v1));  // calls lvalue overload
        g(forward<decltype(v2)>(v2));  // calls rvalue overload
    }