Based on @songyuanyao's Answer, I noticed that my mistake was checking the wrong thing: My intention was to check whether the result of i+j
would bind to a rvalue reference, but I checked whether it is a rvalue reference.
decltype deduces the type based on the value category, not based on what reference type the value would bind to:
1) if the value category of expression is xvalue
, then decltype yields T&&
;
2) if the value category of expression is lvalue
, then decltype yields T&
;
3) if the value category of expression is prvalue
, then decltype yields T
.
As shown in the list, since C++11, rvalues
don't exist as a distinct category on the lowest level. They are now a composite category containing both prvalues
as well as xvalues
. The question as written asks whether the expression is a rvalue reference
and checks whether it is an xvalue
.
From the list above, it is clear that i+j
is a prvalue
, so the third case applies. This explains why decltype(i + j)
is int
and not int&&
. Both xvalues
and prvalues
bind to rvalue references.
So by checking for whether i+j
binds to a lvalue reference
or a rvalue reference
confirms that, indeed, it binds to a rvalue reference
:
void foo(const int& f)
{
std::cout << "binds to lvalue reference" << std::endl;
}
void foo(int&& f)
{
std::cout << "binds to rvalue reference" << std::endl;
}
void test(int i, int j)
{
foo(i); // lvalue -> lvalue ref
foo(std::move(i)); // xvalue -> rvalue ref
// (std::move converts the argument to a rvalue reference and returns it as an xvalue)
foo(i + j); // prvalue -> rvalue ref
}
In conclusion: i+j
is not a rvalue reference, but it binds to one.