4
votes

I'm looking at the standard 5.16 paragraph 3, trying to understand what is going on. Consider the type M defined as

struct M {
  M();
  M(const M&);
  M(M&&);
};

If I have a ternary expression pred ? E1 : E2, where the type of E1 is const M& and the type of E2 is M&& does 5.16 paragraph 3 bullet 1 apply?

— If E2 is an lvalue: E1 can be converted to match E2 if E1 can be implicitly converted (Clause 4) to the type “lvalue reference to T2”, subject to the constraint that in the conversion the reference must bind directly (8.5.3) to an lvalue.

I think it doesn't, because to have an implicit conversion to const M&, which requires M to have the member function operator const M&(). However, I'm not sure, because it could be converted to const M implicitly, can the reference be implicitly added?

If it is implicitly convertible, does M&& bind directly to const M&? I went through the procedure in 8.5.3, and I think that paragraph 5 bullet 2 is where this case falls, so it does bind directly, but I'm not certain.

— If the initializer expression [..] has a class type (i.e., T2 is a class type), where T1 is not reference-related to T2, and can be implicitly converted to an xvalue, class prvalue, or function lvalue of type “cv3 T3”, where “cv1 T1” is reference-compatible with “cv3 T3”

1
What is the definition of T? - Brian Bi
Oh sorry, T should be M, I've updated the question accordingly. - Nick
Expressions don't have reference types. You mean E1 is an lvalue of type const M and E2 is an xvalue of type M. Does this change your question? - user743382
"can be implicitly converted" is defined in [conv]p3. It is more broad than just looking for conversion operators. In this case, const M& x = std::declval<M&&>(); is well-formed, hence M&& (or, an xvalue of type M) is implicitly convertible to const M&. - dyp

1 Answers

5
votes

You don't have expressions of type M&&, instead it would be adjusted to be an xvalue of type M.

So the question is: if you have an xvalue of type M, can it be implicitly converted to lvalue reference to const M? The answer is yes, since a const lvalue reference can be initialized with an rvalue. Such a reference binding is direct since it falls under the following case:

If the initializer expression — is an xvalue (but not a bit-field), class prvalue, array prvalue or function lvalue and “cv1 T1” is reference-compatible with “cv2 T2”, ...

rather than the last case that involves construction of a temporary, which is the indirect binding case.

Therefore this use of the conditional operator will be well-formed. The xvalue of type M will be converted to an lvalue of type const M. Then the lvalue-to-rvalue conversion will be applied and the result will be a prvalue of type const M.