Created on 2014-03-17.00:00:00 last changed 94 months ago
Proposed resolution (October, 2015):
Add the following as a new paragraph following 7.6.16 [expr.cond] paragraph 2:
Otherwise, if the second and third operand are glvalue bit-fields of the same value category and of types cv1 T and cv2 T, respectively, the operands are considered to be of type cv T for the remainder of this section, where cv is the union of cv1 and cv2.
Change 7.6.16 [expr.cond] paragraph 3 as follows:
Otherwise, if the second and third operand have different types and either has (possibly cv-qualified) class type, or if both are glvalues of the same value category and the same type except for cv-qualification, an attempt is made to
convertform an implicit conversion sequence (12.2.4.2 [over.best.ics]) from each of those operands to the type of the other. [Note: Properties such as access, whether an operand is a bit-field, or whether a conversion function is deleted are ignored for that determination. —end note]The process for determining whether an operand expression E1 of type T1 can be converted to match an operand expression E2 of type T2 is defined as follows:Attempts are made to form an implicit conversion sequence from an operand expression E1 of type T1 to a target type related to the type T2 of the operand expression E2 as follows:
If E2 is an lvalue
: E1 can be converted to match E2 if E1 can be implicitly converted (7.3 [conv]) to the type, the target type is “lvalue reference to T2”, subject to the constraint that in the conversion the reference must bind directly (9.4.4 [dcl.init.ref]) to an lvalue.If E2 is an xvalue
: E1 can be converted to match E2 if E1 can be implicitly converted to the type, the target type is “rvalue reference to T2”, subject to the constraint that the reference must bind directly.If E2 is a prvalue or if neither of the
conversionsconversion sequences above can bedoneformed and at least one of the operands has (possibly cv-qualified) class type:
if E1 and E2 have class type, and the underlying class types are the same or one is a base class of the other: E1 can be converted to match E2 if the class of T2 is the same type as, or a base class of, the class of T1, and the cv-qualification of T2 is the same cv-qualification as, or a greater cv-qualification than, the cv-qualification of T1. If the conversion is applied, E1 is changed to a prvalue of type T2 by copy-initializing a temporary of type T2 from E1 and using that temporary as the converted operand.if T1 and T2 are the same class type (ignoring cv-qualification), or one is a base class of the other, and T2 is at least as cv-qualified as T1, the target type is T2,
Otherwise (if E1 or E2 has a non-class type, or if they both have class types but the underlying classes are not the same and neither is a base class of the other): E1 can be converted to match E2 if E1 can be implicitly converted tootherwise, the target type is the type that E2 would have after applying the lvalue-to-rvalue (7.3.2 [conv.lval]), array-to-pointer (7.3.3 [conv.array]), and function-to-pointer (7.3.4 [conv.func]) standard conversions.Using this process, it is determined whether an implicit conversion sequence can be formed from the second operand
can be converted to matchto the target type determined for the third operand, andwhether the third operand can be converted to match the second operandvice versa. If bothcan be convertedsequences can be formed, or onecan be converted but the conversion isformed, but it is the ambiguous conversion sequence, the program is ill-formed. Ifneither can be convertedno conversion sequence can be formed, the operands are left unchanged and further checking is performed as described below.If exactly one conversion is possible,Otherwise, if exactly one conversion sequence can be formed, that conversion is applied to the chosen operand and the converted operand is used in place of the original operand for the remainder of this section. [Note: The conversion might be ill-formed even if an implicit conversion sequence could be formed. —end note]
This resolution also resolves issue 1932.
Notes from the June, 2014 meeting:
The wording should be changed to handle the convertibility test more like overload resolution: the conversion "exists" if the conversion function is declared, but is ill-formed if it would actually be used.
[Adopted at the February, 2016 meeting.]
In an example like,
struct B; struct A { A(); A(B&) = delete; operator B&(); }; struct B : A {} b; B &c = true ? A() : b;
the rules of 7.6.16 [expr.cond] paragraph 3 make this ambiguous: A() can be implicitly converted to the type “lvalue reference to B,” and b satisfies the constraints to be converted to an A prvalue (it's of a type derived from A and the cv-qualifiers are okay). Bullet 3 bullet 1 is clear that we do not actually try to create an A temporary from b, so we don't notice that it invokes a deleted constructor and rule out that conversion.
If the deleted conversion is in the other sense, the result is unambiguous:
struct B; struct A { A(); A(B&); operator B&() = delete; }; struct B : A {} b; B &c = true ? A() : b;
A() can no longer be implicitly converted to the type “lvalue reference to B”: since the declaration B &t = A(); is not well formed (it invokes a deleted function), there is no implicit conversion. So we unambiguously convert the third operand to an A prvalue.
These should presumably either both be valid or both invalid. EDG and gcc call both ambiguous.
History | |||
---|---|---|---|
Date | User | Action | Args |
2017-02-06 00:00:00 | admin | set | status: ready -> cd4 |
2015-11-10 00:00:00 | admin | set | messages: + msg5571 |
2015-11-10 00:00:00 | admin | set | status: drafting -> ready |
2014-07-07 00:00:00 | admin | set | messages: + msg5088 |
2014-07-07 00:00:00 | admin | set | status: open -> drafting |
2014-03-17 00:00:00 | admin | create |