I'm trying to understand everything I can about transfer semantics, rvalue, xvalue, prvalue, etc. I have the following function:
void f(int&& x, int i)
{
std::cout << boost::typeindex::type_id_with_cvr<decltype(x)>().pretty_name();
}
Then I get the output: int&&
Good. So, x, even inside function, is an rvalue reference?
The boost::typeindex::type_id_with_cvr function suggests that, even within the function, input rvalue reference parameter is still an rvalue reference.
However, from what I read on the internet, the rvalue passed to the function, inside the function, becomes lvalue reference.
the rvalue reference from the parameter is only used to select the function from the caller's perspective, it behaves like an lvalue reference inside the function
is rvalue passed as parameter treated as lvalue inside the function?
And so, when inside function f, I've tried to call function f again; suddenly it turned out that x is no longer an rvalue at all:
void f(int&& x, int i)
{
std::cout << boost::typeindex::type_id_with_cvr<decltype(x)>().pretty_name();
i++;
if (i < 10)
{
f(x, i);
}
}
int main(int, char**)
{
int i = 0;
f(50,i);
}
Result: "cannot bind rvalue reference of type ‘int&&’ to lvalue of type ‘int’".
So what is the type of x inside a function after all, and who is wrong here?
I thought this:
50is an rvalue and evaluating the expression50returns an rvalue reference- rvalue reference
int&& xis an lvalue and therefore returns lvalue reference (?)
Is this the correct way of reasoning?
Or is the boost library wrong? Or maybe is compiler returning a bad error?
Why in error massage is lvalue of type int and not int&?
If the parameter behaves as an lvalue reference inside the function (as it says in the stack thread I linked), why doesn't the error say int&?
And I don't mean just to get the answer what is the type of x inside the function. I'm more interested in understanding why the boost library says one thing, the error says something else, and the theoretical knowledge of C++ says something else.
You are mixing two separate concepts, and are getting royally confused.
xinsidefis an rvalue reference, because it is declared as suchxwhen it appears insidefis an lvalue (unless it is located in areturnstatement)xis an rvalue reference when talking about the function parameter, butxis an lvalue when talking about the expression as it appears in other code. When you understand the difference, all your questions are easy to answer:Yes, the parameter
xof the functionfis an rvalue reference. That's exactly whatdecltype(x)gives you: the declared type, as the name suggests.This is inaccurate. The function parameters are lvalues when they appear in an some expression, but what type they have depends entirely on how you've declared the function. For example:
The type of the expression
xisint, and the value category of the expressionxis lvalue. The type of the function parameterxisint&&.50is a prvalue, but evaluating it doesn't produce a reference. It produces a temporary object of typeint.That sentence doesn't make sense. A type isn't inherently an lvalue or rvalue. The value category depends on the expression and the context in which
xis used.Because the type of the parameter
xisint&&. If you usedecltype, that's exactly what it tells you.The type of the parameter
xisint&&, and the type of the expressionxisint. The boost utility you're using works based on the type of the parameter, not based n the type of an expressionx.If you wanted to, you could obtain the type of the expression
xbe with:This is obviously different from
decltype(x), which yields the type of the declaration.