First of all, the result of the conditional operator is either a glvalue designating the selected operand, or a prvalue whose value comes from the selected operand.
Exception as noted by T.C.: if at least one operand is of class type and has a conversion-to-reference operator, the result may be an lvalue designating the object designated by the return value of that operator; and if the designated object is actually a temporary, a dangling reference may result. This is a problem with such operators that offer implicit conversion of prvalues to lvalues, not a problem introduced by the conditional operator per se.
In both cases it is safe to bind a reference to the result, the usual rules for binding a reference to an lvalue or a prvalue apply. If the reference binds to a prvalue (either the prvalue result of the conditional, or a prvalue initialized from the lvalue result of the conditional), the lifetime of the prvalue is extended to match the lifetime of the reference.
In your original case, the conditional is:
true ? a : 2.
The second and third operand are: "lvalue of type float
" and "prvalue of type double
". This is case 5 in the cppreference summary, with the result being "prvalue of type double
".
Then, your code initializes a const reference with a prvalue of a different (non-reference-related) type. The behaviour of this is to copy-initialize a temporary of the same type as the reference.
In summary, after const float & x = true ? a : 2.;
, x
is an lvalue denoting a float
whose value is the result of converting a
to double
and back. (Not sure off the top of my head whether that is guaranteed to compare equal to a
). x
is not bound to a
.
In bonus case 1, the second and third operand of the conditional operator are "lvalue of type float
" and "lvalue of type const float
". This is case 3 of the same cppreference link,
both are glvalues of the same value category and have the same type except for cv-qualification
The behavour is that the second operand is converted to "lvalue of type const float
" (denoting the same object), and the result of the conditional is "lvalue of type const float
" denoting the selected object.
Then you bind const float &
to "lvalue of type const float
", which binds directly.
So after const float & x = true ? a : b;
, x
is directly bound to either a
or b
.
In bonus case 2, true ? a_ref : 2.
. The second and third operands are "lvalue of type const double
" and "prvalue of type double
", so the result is "prvalue of type double
".
Then you bind this to const double & x
, which is a direct binding since const double
is reference-related to double
.
So after const double & x = true ? a_ref : 2.;
, then x
is an lvalue denoting a double with the same value as a_ref
(but x
is not bound to a
).