Search code examples
c++forwarding-reference

Why is Universal reference being treated as R-Value reference?


#include <iostream>

class A
{
public:
    A() {};
};

template <class T>
class Test
{
public:
    void func1(T&& t)
    {

    }
};

int main()
{
    A a;
    Test<A> o1;

    o1.func1(a); 

    return 0;
}

Following errors are seen on compilation

error C2664: 'void Test<A>::func1(T &&)': cannot convert argument 1 from 'A' to 'T &&'
note: You cannot bind an lvalue to an rvalue reference

o1 is obtained by instantiating template class Test with "A". So the call o1.func1(a) should know that void func1(T&& t) should resolve to void func1(A&& t)

I thought T&& in void func1(T&& t) should be deduced as a universal reference or a forwarding reference because its from a template type parameter. Then why in the error above it says "You cannot bind an lvalue to an rvalue reference"?

Am i missing some template magic here?


Solution

  • I thought T&& in void func1(T&& t) should be deduced as a universal reference or a forwarding reference [...]

    No. t in your example is not a universal reference. To be a universal reference it must be deduced from the call, but in your example T is just A. This is a universal reference:

    template <class T>
    class Test
    {
    public:
        template <typename X>
        void func1(X&& t)
        {
    
        }
    };
    

    The important detail is "deduced". In your example nothing is being deduced. Consider that Test<A> is equivalent to

    class TestA
    {
    public:     
        void func1(A&& t)
        {
    
        }
    };
    

    Once you instantiated the class template, its method func1 has argument of tpye A&&, not something else, ie there is nothing to be deduced anymore. Template argument deduction takes place when you do not explicitly state the template argument, as in

     template <typename T> void foo(T&& t) {};
     
     foo(1);