Date: Fri, 14 Jul 2023 14:26:31 +0300
On 7/14/23 13:21, Daniel Krügler wrote:
> Am Fr., 14. Juli 2023 um 01:49 Uhr schrieb Andrey Semashev via
> Std-Discussion <std-discussion_at_[hidden]>:
>>
>> Hi.
>>
>> Recently I got bitten by this innocent piece of code:
>>
>> struct comparible_UDT
>> {
>> int i_;
>> comparible_UDT() : i_(2){}
>> bool operator == (const comparible_UDT& v) { return v.i_ == i_; }
>> };
>>
>> bool test(comparible_UDT left, comparible_UDT right)
>> {
>> return left == right;
>> }
>>
>> This used to work fine until C++20, where the completely broken piece
>> of... core language called operator rewriting appeared. Now gcc and
>> clang mercifully accept this code, albeit with a warning, and MSVC fails
>> to compile it saying the operator== is ambiguous with its rewritten
>> self. Which, of course, I did not write and cannot suppress.
>>
>> https://godbolt.org/z/hsfE8sYfG
>>
>> (Yes, I know I can fix this by marking the operator== as const, that's
>> not the point. The point is that the code above should work as written,
>> there's nothing ambiguous about it.)
>
> Alternatively you could define
>
> bool operator!=(const comparible_UDT& v);
>
> if the non-const operator== was by design.
>
> And if you think that user code should not attempt to call operator!=
> for some reason, you could change the definition to
>
> bool operator != (const comparible_UDT& v) = delete;
Thanks, at least it is possible to preserve the definition of operator==
unchanged. Although this workaround seems completely unnecessary, given
that operator!= is never used in the code, yet it affects operator==.
>> Could someone explain the rationale behind making this code invalid in
>> C++20? Is there a rationale at all?
>
> It is documented as breaking change in Annex C, [diff.cpp17.over].
>
>> If there isn't, is this a bug? Should it be reported as a DR?
>
> This kind of problem was foreseen but was still accepted. I think it
> wont be accepted as an issue, unless you provide additional
> information why this is a non acceptable change.
>
> I can understand that this is unfortunate, but almost unpreventable
> when the language is willing to make progress with acceptable costs.
> Just as a complete different example: You would have had a similar
> breaking change if your pre-C++20 code did have a variable named as
> "consteval", for example, which was then introduced as keyword.
I don't think it was unavoidable, so the example with new keywords
doesn't apply. At least, gcc and clang seem able to "do the right thing"
by preferring the "normal" operator== over the synthesized reversed one
during overload resolution. I think, [over.match.best] should have been
updated to that effect. For example, the paragraph 2.9 should not have
the "F1 and F2 are rewritten candidates" condition, and always prefer
the non-reversed candidate.
> Am Fr., 14. Juli 2023 um 01:49 Uhr schrieb Andrey Semashev via
> Std-Discussion <std-discussion_at_[hidden]>:
>>
>> Hi.
>>
>> Recently I got bitten by this innocent piece of code:
>>
>> struct comparible_UDT
>> {
>> int i_;
>> comparible_UDT() : i_(2){}
>> bool operator == (const comparible_UDT& v) { return v.i_ == i_; }
>> };
>>
>> bool test(comparible_UDT left, comparible_UDT right)
>> {
>> return left == right;
>> }
>>
>> This used to work fine until C++20, where the completely broken piece
>> of... core language called operator rewriting appeared. Now gcc and
>> clang mercifully accept this code, albeit with a warning, and MSVC fails
>> to compile it saying the operator== is ambiguous with its rewritten
>> self. Which, of course, I did not write and cannot suppress.
>>
>> https://godbolt.org/z/hsfE8sYfG
>>
>> (Yes, I know I can fix this by marking the operator== as const, that's
>> not the point. The point is that the code above should work as written,
>> there's nothing ambiguous about it.)
>
> Alternatively you could define
>
> bool operator!=(const comparible_UDT& v);
>
> if the non-const operator== was by design.
>
> And if you think that user code should not attempt to call operator!=
> for some reason, you could change the definition to
>
> bool operator != (const comparible_UDT& v) = delete;
Thanks, at least it is possible to preserve the definition of operator==
unchanged. Although this workaround seems completely unnecessary, given
that operator!= is never used in the code, yet it affects operator==.
>> Could someone explain the rationale behind making this code invalid in
>> C++20? Is there a rationale at all?
>
> It is documented as breaking change in Annex C, [diff.cpp17.over].
>
>> If there isn't, is this a bug? Should it be reported as a DR?
>
> This kind of problem was foreseen but was still accepted. I think it
> wont be accepted as an issue, unless you provide additional
> information why this is a non acceptable change.
>
> I can understand that this is unfortunate, but almost unpreventable
> when the language is willing to make progress with acceptable costs.
> Just as a complete different example: You would have had a similar
> breaking change if your pre-C++20 code did have a variable named as
> "consteval", for example, which was then introduced as keyword.
I don't think it was unavoidable, so the example with new keywords
doesn't apply. At least, gcc and clang seem able to "do the right thing"
by preferring the "normal" operator== over the synthesized reversed one
during overload resolution. I think, [over.match.best] should have been
updated to that effect. For example, the paragraph 2.9 should not have
the "F1 and F2 are rewritten candidates" condition, and always prefer
the non-reversed candidate.
Received on 2023-07-14 11:26:36