Compilation error with C++20 standard: unable to rewrite operator!= because operator== does not return a bool

Description

Hello,

In C++20, secondary comparaison operators are possibly rewritten from their primary operators. This, generally, is not a concern as far as the operator== retturns a boolean. This is not the case as the UBool is an integer. As a matter of fact, the compiler is not able to rewrite the operator!=. We have to help it a little: I will give a PR soon.

To reproduce:

Regards,
Stac

Activity

Fredrik Roubert September 28, 2023 at 1:33 PM

I've now verified that ICU4C at current HEAD (ie. that which will become ICU 74 in a few weeks) builds fine with -std=c++20 with Clang 16 also without -Wno-ambiguous-reversed-operator. So my comment from two years ago, it seems as if this warning might actually be overzealous and might be changed in the future, turned out to be right.

Markus Scherer September 27, 2023 at 9:44 PM
Edited

Response today from a Google C++ expert:

It shouldn't be a big deal to fix since https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2468r2.html was implemented in https://github.com/llvm/llvm-project/commit/38b9d313e6945804fffc654f849cfa05ba2c713d.

Effectively, if you make sure you to implement both operator== and operator!=, you're good.

I replied:

ICU implements polymorphic operator==() in class hierarchies, where the operator takes a reference to the hierarchy's base class. We normally inherit the operator!=() from the base class like this:

rather than repeating the exact operator!=() definition in each subclass.

Are you saying that if we did repeat this exact definition in each subclass, then we could build with a C++20 compiler that implements P2468R2?

The expert replied back:

You don't need to even make such a change. You can leave code as in your example as it is -- C++20 was fixed such that your code is no longer incompatible with it.

By defining both an operator== and a operator!= with the same argument types (even if the latter has been inherited), automatic creation of a reversed operator== is disabled, so you now preserve the same semantics you had in C++17.

See test code with Clang 15 (before P2468 was implemented) vs Clang 16 (after): https://godbolt.org/z/YsYqfExdK

Markus Scherer May 12, 2022 at 5:33 PM

My summary of a recent look at item 3 of Fredrik’s 2021-aug-06 comment:

Polymorphic operator==() will only work as long as we can keep -Wno-ambiguous-reversed-operator (look for that in icu4c/source/configure.ac). C++20 creates an operator==() with reversed arguments, putting the base class (e.g., Format) on the left. This makes call sites ambiguous. It seems like the only remedy would be to move the virtual equality function to one with a new name like “equals()”, and change operator==() to not be virtual and to just delegate to equals(). This would break long-stable subclassing API. At the same time, whatever issues this is intended to solve for implementations of operator==() would just be moved to a function with a non-special name.

Fredrik Roubert August 26, 2021 at 9:09 PM

It’s definitely possible that there now still are equality operators in ICU4C that are possible to call in ways that are ambigious in C++20 even though they’re never called in such ways by the ICU4C implementation and test code, but if someone encounters that in the future, I propose that they then file new tickets to fix these on a case-by-case basis.

Fredrik Roubert August 26, 2021 at 2:14 PM

The workarounds made for “2. Use of overloaded operator '!=' is ambiguous (error)” have now been replaced with instead changing the code so that no workarounds are needed.

Fixed

Details

Assignee

Reporter

Components

Priority

Time Needed

Weeks

Fix versions

Created February 12, 2020 at 1:04 PM
Updated September 6, 2024 at 4:58 PM
Resolved August 26, 2021 at 9:10 PM