-
Notifications
You must be signed in to change notification settings - Fork 7
CWG3000 [over.match.oper] Conditional operator is not handled despite false claim in note #679
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Note that Note 1 is ancient C++98 wording. From what I can tell, the note has been wrong from the start and no one noticed until now. See https://www.open-std.org/jtc1/sc22/wg21/docs/wp/html/nov97-2/ |
CC @t3nsor |
I'm not sure we need [expr.cond] p6 anymore, given all the implicit conversions applied in p4. Any example to the contrary? |
@jensmaurer see the reflector discussion. We run into a case with the example in CWG2321 where one side is I'm not sure if there are other cases, and even this one may be unintentional. I also would be opposed to removing this whole overload resolution mechanism and explaining what happens directly in p6. It's pretty convoluted for what it does. |
We can massage p7.1 to ignore const differences (see my reflector message). |
CWG3000 fixes this by removing the overload resolution rule. |
The purpose of [expr.cond]/6 is to make the following work: struct X { operator int() { return 1; } };
struct Y { operator int() { return 2; } };
int i = false ? X() : Y();
assert(i == 2); Removing the paragraph outright seems misguided. For CWG2321, I think the correct fix would be to apply the conversion at the end of p4 to both operands:
The issue pointed out by the OP is that [expr.cond]/6 says "overload resolution is performed" with a cross-reference to [over.match.oper], but the latter does not actually tell us what that means (i.e. what the candidates are). I think inserting a new paragraph somewhere in [over.match.oper] addressing this case should be sufficient; we don't need to group it with the other operators since it's special and can't be overloaded.
|
CWG3000 has been updated to address a bag of concerns. |
Thanks. The new P/R still has some issues:
On a related note, the resolution of CWG2865 also seems wrong: the intent (per the description of the issue and the discussion in #442) was to have the conditional operator with operands "lvalue of type Here's an alternative wording suggestion for the updated CWG3000: Edit 7.2.2 [expr.type] p3:
Edit 7.3.6 [conv.qual] p3:
Edit 7.6.16 [expr.cond] p3:
Edit 7.6.16 [expr.cond] p4:
Add a new paragraph to 12.2.2.3 [over.match.oper]:
The changes can be summarized thusly (with the help of
Notably, this preserves the questionable status quo that expressions converted to non-reference types sometimes needlessly propagate their original cv-qualification into the type of the resulting prvalue (e.g.
|
We shall not use meta-stuff defined in the library section for core language definitions, ever. I understand the edits using "qualification-combined" in the existing scenarios are wrong, because they aim to copy top-level cv-qualification, but "qualification-combined" doesn't. I'm wondering whether we should just revert that part, instead of changing the definition of "qualification-combined". |
The proposed wording does not use it. It only appears in the (informal) summary of what the proposed wording does, as a convenient shortcut for "the result of the conditional operator with the operands ..." I've un-collapsed the proposed wording to make it clearer. |
So, I think we should leave expr.type and conv.qual mostly alone, adding just "longest" and "The value is unchanged" to the latter (which are simple drive-by fixes). If there is something wrong with composite pointer type, that should be a separate core issue. |
Let's take the rest piecemeal. First, the [over.match.oper] fix looks mostly good; we still need to map the operator syntax to a (hypothetical) function call to make the connection to [over.built]. Done in CWG3000 (at the bottom). |
For the first two bullets of the (current p4), I don't think we'll ever have different (but similar) target types when the conversion works both ways. |
Hm... If E2 is the "prvalue of type X", we don't form a conversion sequence per the text added by CWG2865. |
Hm... I'm not seeing how the suggested resolution handles "true ? T() : T()" (should simply yield a prvalue of type T) correctly. It seems we form no conversion sequence at all. |
Okay, but then we need another way to compute the composite result type to make the example with pointers from CWG3000 work. This would probably involve using "qualification-combined type" in some form anyway, perhaps by inventing some pointer types and talking about the cv-combined type of those... which doesn't seem ideal (but we already do something similar for "reference-compatible", so maybe it's not that bad). Changing "qualification-combined type" feels like a better approach to me; it's only used in two places at the moment.
Yes, that's true in the current version. I got confused there; sorry.
I agree. This produces an lvalue, but before CWG1895 the result was a prvalue, and the ostensible goal of CWG2865 was to restore that. (All major implementations produce a prvalue.)
This case is handled by p3: it merges the cv-qualifiers of the second and third operands (a no-op in this case). We then skip p4 (because of the "Otherwise, ..."), and eventually reach p7.1 as expected. |
I've updated CWG3000; two main themes:
|
In the case where neither operand has class type, the first conversion of p4 should always work in both directions, so I don't think we need this part anymore:
I realized after initially sending this reply that, per CWG2898, it is intended that an implicit conversion sequence from Suggestions possibly voided by CWG2898I would additionally suggest removing "second and third operand have different types" from p4. Consider: struct X {
X();
X(X&);
};
using CX = const X;
CX cx;
auto r1 = true ? X() : cx;
auto r2 = true ? CX() : cx;
Also consider: struct X {
X();
X(X&);
operator int() volatile;
};
volatile X vx;
auto r3 = true ? static_cast<X&&>(X()) : vx;
auto r4 = true ? static_cast<volatile X&&>(vx) : vx; None of the p4 conversions work in this example. For
There's another (preexisting) issue with p4. I'm not sure whether that's something that should be addressed as part of this issue (or at all), but I'll mention it here for completeness. When attempting to form an implicit conversion sequence from struct X {
operator int() volatile;
};
volatile X vx;
auto r5 = true ? vx : X();
We could say that the the ICS in p4 can be formed only if both operands are convertible to its target type, which would allow |
Removed. See CWG3000. |
Reference (section label): [over.match.oper]
Link to reflector thread (if any): https://lists.isocpp.org/core/current/17459.php
Issue description
[over.match.operator] Note 1 states:
However, there exist no rules in [over.match.oper] which apply to the conditional operator. These rules are needed when overload resolution is requested by [expr.cond] paragraph 6.
Suggested resolution
Append a row to [tab:over.match.oper] with the following contents:
Underneath [tab:over.match.oper], within the same paragraph, append the following:
Editor's note: The intent is that for
a ? b : c
, anoperator bool
for the condition is only meant to be evaluated once. [expr.cond] paragraph 1 already performs such contextual conversion, and we wouldn't want to evaluateoperator bool
a second time just because we fall into [expr.cond] p6. Alternatively, we could remove thebool
parameter in [over.built] and translatea?b:c
intooperator?:(b,c)
for the purpose of overload resolution.Change [over.match.oper] paragraph 3 as follows:
Editor's note: Specifying cv1
T1
etc. in this case is not necessary because the third bullet applies to conditional operator, and the third bullet does not use these definitions.Further notes
Even if there were rules to translate
a?b:c
intooperator?:(a,b,c)
, [over.built] has no built-in candidate foroperator?:
that accepts class types. Therefore, the resolution of CWG2321 is incomplete (see linked reflector), but that is a separate defect (discovered by Brian Bi).The text was updated successfully, but these errors were encountered: