What is the type of an rvalue reference parameter inside a function? [duplicate]
Asked Answered
P

1

5

I have a really simple function definition here:

void testRvalue(int&& r)
{
    printf("rvalue ref is called\n");
    testRvalue(r); // this line gives "no known conversion from 'int' to 'int &&' for 1st argument"
}

I mean inside this function, what is the type of r? Isn't it int&& (the parameter is int&& r so how come r is not of type int&&?) If so why can't I pass this r to this function itself, which takes a int&& type as parameter?

What is the type of r exactly? int&& or int? If int, why?

Pennsylvanian answered 10/2, 2021 at 5:30 Comment(0)
S
10

A very good read is Value categories.

Yes, the type of the variable r is indeed int&&. However what matters here is the expression and:

Each C++ expression (an operator with its operands, a literal, a variable name, etc.) is characterized by two independent properties: a type and a value category. Each expression has some non-reference type, and each expression belongs to exactly one of the three primary value categories: prvalue, xvalue, and lvalue.

The expression r is an lvalue:

lvalue

The following expressions are lvalue expressions:

  • the name of a variable [...], regardless of type. Even if the variable's type is rvalue reference, the expression consisting of its name is an lvalue expression;

Rvalue references can bind to prvalues or xvalue but not to lvalues so if you want to bind an rvalue reference to r you need to convert r to an xvalue. This is done with std::move which despite its name is just an cast.

You can easily reason about this like so: if it has a name then it's an lvalue (even if the type of that id is rvalue reference). You can't bind rvalue references (which in principle should bind to temporary objects) to something that has a name. Something that has a name can be reused. You need std::move to enable move from that lvalue.

Regarding the message which says "no known conversion from 'int'". As shown above the type of the expression r is int, however a more appropriate diagnostic message would have been something along the lines: "rvalue reference cannot bind to lvalue".

And indeed newer clang and gcc give better messages:

gcc

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

clang

candidate function not viable: expects an rvalue for 1st argument

Siloa answered 10/2, 2021 at 5:43 Comment(1)
It took me a while to realize the whole thing evolved around expressions, not variables.Karlow

© 2022 - 2024 — McMap. All rights reserved.