Consider these cases:
int i{};
int& ir{i};
class A{
public:
int& i;
A(int&& pi):i(pi){}
};
A a1{i}; // Error // case 1
A a2{int(1)}; // OK // case 2
class B{
public:
int& i;
template<typename TYPE>
B(TYPE&& pi):i(pi){}
};
B b1{i}; // OK // case 3
B b2{int(1)}; //OK // case 4
int& ii{int(12)}; // Error // case 5
int& iii{std::move(int(12))}; // Error // case 6
template<typename TYPE>
class C{
public:
TYPE& i;
C(TYPE&& pi):i(pi){}
};
C c1{i}; // Error // case 7
C c2{int(1)}; // OK // case 8
C<int&> c3{i}; // OK // case 9
C<int&> c4{int(1)}; // Error // case 10
int&& iiii{ir}; // Error // case 11
A rvalue can not be bound to lvalue and if my understanding is correct, TYPE&& would either collapse to TYPE&& or TYPE&.
How ever I am having a hard time understanding these cases, specially case 4. If case 4 is correct, then it means we have b2.i which is a reference, initialized from a temporary (rvalue). Then why case 2, 5, 6 and 7 are incorrect? And when case 9 is correct it mean the TYPE&& is int&&& which (I assume) collapses to int& , then how could c3.i which is an rvalue(int&&) be initialized from a lvalue, while case 10 and 11 are incorrect?
I wish some one could explain the general rules regarding this subject and also these cases in detail.
There are several mechanisms at play here: lvalue/rvalue semantics, reference collapsing, forwarding reference and CTAD. I think explaining the cases you listed should be sufficient to form a big picture.
int&& pican't be bound to lvaluei.int&& pican be bound to rvalueint(1).piini(pi)refers to a memory location so it is an lvalue, allowinga2.ito be initialized. After constructiona2.iis a dangling reference toint(1).TYPE&& pican be bound to lvaluei.TYPEisint&.b1.irefers toi.TYPE&& pican be bound to rvalueint(1).TYPEisint.TYPE&& piis an rvalue reference, similar to case 2b2.iis a dangling reference toint(1).int& iican not be bound to rvalueint(12).int& iiican not be bound to rvaluestd::move(int(12)).In cases 7-10
TYPE&& piis not a forwarding reference becauseTYPEis a template parameter ofclass C, not of constructor. CTAD, used in 7-8 to deduceTYPE, doesn't change that: an rvalue is expected, only thenTYPEcan be deduced toint, formingint&& pi.TYPEcan't be deduced.TYPEis deduced to beint.c2.i, declared asint& i;, forms a dangling reference toint(1).TYPEis explicitlyint&.TYPE&& piis collapsed toint& pi.TYPE& iis collapsed toint& i.c3.irefers toi.TYPE&& piis collapsed toint& pi, lvalue reference can't be bound toint(1).int&& iiiican't be bound to lvalueir.And a bonus case that might make cases 2 and 4 easier to understand:
The first line is correct, the last is an error.
int&& rvris an rvalue reference and extends lifetime of a temporary. Butrvrmentioned in the last line is an lvalue, so rvalue referenceint&& rvr2can't be bound to it.