However it does not compile, why? Does g(x) return a temporary object? If so, then its type must be int&& and yet the error list contains these two lines:
* initial value of reference to non-const must be an lvalue
* 'initializing': cannot convert from 'int' to 'int &'
in other words, shouldn't the error say "cannot convert from 'int&&' to 'int&'" ?
Not exactly. g(some_double) is a prvalue expression. (A temporary object is produced when required.)
i(some_double) always returns a dangling reference. The dangling reference is bound to the temporary object materialized from g(x). The materialized temporary lives until the semicolon at the end of the return statement.
Note that the problem occurs here: auto& li = i(8.8).
For the purposes of reference initialization the referenced object is considered instead of the reference.
Consider:
1 2 3
int g = 24;
int& x = g; // x refers to g
int& y = x; // y refers to g, not to x
(The type of an expression is never a reference type).
Technically, you're right.
My understanding is that the standard adjusts the type of the expression from a reference type to a non-reference type to enable referential transparency when specifying the meaning of expressions. https://timsong-cpp.github.io/cppwp/n4659/expr#5
Consider:
1 2 3 4 5
#include <type_traits>
int&& i(double);
static_assert(std::is_same<decltype(i(8.8)), int&&>::value,
"i(8.8) has reference type");
However, I'm not convinced that this rule is more than an implementation detail, and I'm not sure it should be taught. (The rule does explain the error message, at least.)
> Actually, the error should be: lvalue reference cannot bind to an xvalue Shouldn't it?
Well, these are pretty close.
I suppose it is simpler to emit the same error text for all rvalues (both xvalues and prvalues):
1 2 3 4 5 6 7 8
int&& foo() ;
int main()
{
[[maybe_unused]] int& r = foo() ;
// g++ - error: cannot bind non-const lvalue reference of type 'int&' to an rvalue of type 'int'
// clang++ error = : non-const lvalue reference to type 'int' cannot bind to a temporary of type 'int'
}