How does C ++ make template inference to an rvalue reference?

template<typename T>
void foo(T&& arg);

      

I know if arg is an lvalue for example. int x = 0; foo(x);

, then the T = int&

function will be foo(int& &&)

that foo(int&)

.

if arg is the value of r, eg. foo(0)

; then the T = int

function will be foo(int&&)

.

What if I have

template<typename T>
void foo(T& arg);

template<typename U>
void bar(U&& u)
{
    foo(u);
}

      

What will be T

in foo

when you call bar(0)

?

+3


source to share


3 answers


template<typename U>
void bar(U&& u)
{
    foo(u);
}

      

No matter what you pass in bar

, u

is the value of an lvalue, as it has a name.

u

can be an lvalue reference or an rvalue reference, but when you pass it to foo

, its "reference" is ignored as usual.

Forget about lvalues โ€‹โ€‹and rvalues โ€‹โ€‹and templates for a moment. The reference is assumed to be an alias for another variable, and generally when referring to the reference by name, you should behave as if you were referring to the original variable:

int i = 42;
int& r = i;

f(int);
f(int&);
f(i); // error: call to ambiguous overload
f(r); // error: call to ambiguous overload

g(int);
g(r); // OK, pass by copy, reference-ness of r is irrelevant

h(int&);
h(i); // OK, pass by reference, non-reference-ness of i is irrelevant

      



In the above operators, the functions id are expressions i

and r

are values โ€‹โ€‹of type int

. The fact that the variables i

and r

are minor, and the reference, respectively, has nothing to do with the type or value of the corresponding identifiers-identifiers. This is how links have always worked, and rvalue links don't change that.

template<typename T>
void foo(T& arg);

      

There is nothing you can pass to foo

that makes it a T

reference type. arg

will always be an lvalue reference.

If you want to spread the category of argument values, you need std::forward

:

template<typename U>
void baz(U&& u)
{
    foo(std::forward<U>(u));
}

baz(42); // error: attempted to call foo() with an rvalue

      

+3


source


This must be what U ends up with, so if U is an int it will be

bar(int&& u)
{
    foo(u);
}

      



passing int to foo.

0


source


What if I have

template<typename T>
void foo(T& arg);

template<typename U>
void bar(U&& u)
{
    foo(u);
}

      

What is T in foo when calling bar (0)?

This may sound a bit surprising, but using rvalue-reference is an lvalue expression, which means that u

in foo(u)

is an lvalue , and that's okay for a function that accepts an lvalue-reference (in this case foo

.

That is bar(0)

, the specializations used for the call :

bar<int>(int&&)
foo<int>(int&)

      

For int value; bar(value);

specialization will be:

bar<int&>(int& &&) // i.e. int&
foo<int>(int&)

      

0


source







All Articles