Question

I wanted to know how this is possible ?

template<typename T>
void Test(T&& arg)
{
    arg = 14;
}


int a = 23;
Test(a);

My question is that the function Test requires an argument of type Rvalue however it seems to also accept parameter of type lvalue. Why is that ? Is that because of presence of templates ? Because If i do something like this

void AnotherTest(int&& arg)
{
    arg = 14;
}

Then the function requires the parameter to be of type Rvalue. I would appreciate it if someone could explain why presence of Templates changes the behavior.

Was it helpful?

Solution

The key, as you correctly imagined, is that it is a template and that the argument type is being deduced. When you call Test with an lvalue, the rules for argument type deduction when the argument is an rvalue-reference will deduce the type T to be an lvalue-reference, and thus the specialization becomes:

template <>
void Test<int&>(int & && arg)

At this point the reference collapsing rules kick in and the type of the argument becomes:

template <>
void Test<int&>(int & arg)

While the template takes an rvalue-reference, if the type is an lvalue-reference the argument becomes an lvalue-reference itself.

OTHER TIPS

Is that because of presence of templates ?

Somewhat, but not strictly speaking. More precisely, this behavior occurs because you have an alias for a reference type. A template parameter is the most likely scenario where you would see this, but you can synthesize the behavior without templates.

using T = int&; // Alias, not a template parameter

void AnotherTest(T&& arg)
{
    arg = 14;
}

Instead of using a template parameter as an alias, I've employed the using keyword (a typedef would also work). Just like in your template setup, an rvalue reference to an lvalue reference collapses to an lvalue reference. That is, T&& is the same as T in this case. So you can invoke AnotherTest(a) and have arg bind to a.


On the flip side, you can keep your template and still replicate the error. The key is to specify the template argument instead of letting it be deduced.

    Test<int>(a);

error: cannot bind rvalue reference of type 'int&&' to lvalue of type 'int'

The gist of the above is that you probably misunderstood what the compiler deduced your template parameter as. When you invoked Test(a), you probably thought T was int, but your compiler – which has the final say in the matter – decided that T was int&.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top