[Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

Marc Mutz marc.mutz at qt.io
Tue Nov 7 18:07:10 CET 2023


On 07.11.23 15:28, Ivan Solovev via Development wrote:
> 
> So, my question is - shoud we support mixing C++17 and C++20 in one binary?

To be clear: This is not about Qt compiled with C++17 used in projects 
compiled with C++20. This is about one .cpp file being compiled with 
C++17 and another .cpp file from, broadly speaking, the same cmake 
target, in C++20 (static builds are different; there, the whole 
application incl. all "statically-linked libraries", is one executable).

What will happen is that the first TU is using a Q*Ordering return type 
and the second TU is using the std::*_order return type. The linker will 
them de-duplicate these per-TU inline function bodies and pick one of 
them. Lets say, for the sake of argument, the C++17 one. Since the two 
sets of ordering types are not binary compatible, and equivalent states 
have different numerical values, the result of the call to the function 
in the C++20 TU will be misinterpreted when it comes from the C++17 
function. Of course, the whole thing is UB, so we may not even get so 
far as a possible misinterpretation.

There are several ways to solve this:

1. Ban mixing different C++ versions in the same executable (= cmake 
target).

This is probably the safest. If we allowed this instead, we'd need to 
review all of our APIs to see whether we have a similar issue already.

2. always use only the Q*Ordering types.

Esp. since the numerical values of std::*_ordering and Q*Ordering don't 
match, this will inject value-mapping code in future-proof idiomatic 
C++20 code like

    switch (lhs <=> rhs) {
    case std::strong_order::less: ~~~;
    ~~~;
    }

I would very much like to avoid that overhead.

3. make the Q*Ordering types binary compatible with the std ones.

If they're binary compatible, then while technically UB (ODR violation) 
the situation would be very much like any other change to inline API.

There are two issues here: First, different std libs have different 
values for the different states, so we'd need to #ifdef our own enum to 
what the currently-used stdlib is using. Second, QPartialOrdering was 
released independent of the C++20 comparison work, in Qt 6.0. So we 
would need to dissociate the C++20 comparison stuff from it and rename 
the existing 6.7 Q*Ordering types to, say, Qt:*_ordering, to start with 
a clean slate.

My opinion:
- 1 is simplest, but we don't control how users compile our APIs, so 
someone may still trigger this
- 3 is cleanest, therefore preferred: the complexity is on us, but the 
resulting code is as efficient as can be, regardless of C++17 or C++20. 
This is how it should be in C++.
- I don't like 2. It has it all backwards.


Thanks,
Marc

-- 
Marc Mutz <marc.mutz at qt.io>
Principal Software Engineer

The Qt Company
Erich-Thilo-Str. 10 12489
Berlin, Germany
www.qt.io

Geschäftsführer: Mika Pälsi, Juha Varelius, Jouni Lintunen
Sitz der Gesellschaft: Berlin,
Registergericht: Amtsgericht Charlottenburg,
HRB 144331 B



More information about the Development mailing list