Search code examples
c++referencervalue-referenceuniversal

Does something wrong with Widget&& var1 = someWidget;?


recently, i began to learing something about universal reference https://isocpp.org/blog/2012/11/universal-references-in-c11-scott-meyers and it says that Widget&& var1 = someWidget; //here, "&&" means rvalue reference. i know that "&&" can be universal reference or rvalue reference,but i thought somewidget must be a lvalue, and there is no deduce here, so Widget&& && must be rvalue reference, and here is the question. can rvalue reference accept a lvalue, i have learnt that lvalue reference can accept lvalue, and const lvalue reference can accept rvalue, but rvalue reference can only accept rvalue, so is there something wrong with this statement ? or something i miss


Solution

  • I found that blog post to be confusing. I'd recommend reading a good chapter in a book or the standard itself instead of that post. Part of the problem is that the blog post is 10 years old, so people were still thinking about the new features and how to teach them. I don't think that code even compiles though. I tested int a = 5; int &&b = a; and got a compile-time error as expected. I think he meant something like widget{} by someWidget. int &&j = int{5}; compiles fine.

    However, if you have a template function like void f(T &&t), it can turn into an lvalue reference or an rvalue reference, depending on what is passed to it. The main point of that is to implement perfect forwarding. The old way to do that was to innumerate all possible combinations of arguments, which is exponential in the number of arguments taken. Now, you can write one function that can call other functions with as much efficiency as possible, using the fact something is an rvalue if it is one. Consider the following example:

    struct W
    {
       W(int &, int &) {}
    };
    
    struct X
    {
       X(int const &, int &) {}
    };
    
    struct Y
    {
       Y(int &, int const &) {}
    };
    
    struct Z
    {
       Z(int const &, int const &) {}
    };
    
    template <typename T, typename A1, typename A2>
    T* factory(A1 &&a1, A2 &&a2)
    {
       return new T(std::forward<A1>(a1), std::forward<A2>(a2));
    }
    
    int main()
    {
       int a = 4;
       int b = 5;
       W *pw = factory<W>(a, b);
       X *px = factory<X>(2, b);
       Y *py = factory<Y>(a, 2);
       Z *pz = factory<Z>(2, 2);
    
       delete pw;
       delete px;
       delete py;
       delete pz;
    }