[Development] Notes from "C++17 language and std library features for Qt 6"

Kari Oikarinen kari.oikarinen at qt.io
Wed Nov 20 20:20:29 CET 2019


Hi!

Here are the notes for the C++17 related session held today at QtCS. I
tried my best to capture the discussion, but there might still be a lot
of errors.

Notes are also in the wiki at 
https://wiki.qt.io/Qt_Contributor_Summit_2019_-_C%2B%2B17_Features_Notes

# Language


## if constexpr

# Language


## if constexpr

Very useful for our containers.


## Fold expressions

Shortcut for handling parameter packs of vadiadic templates. No need
to write recursive template helpers.


## Inline variable

Volker: What is the impact of using inline variables to static data
initialization? How do we deal with `Q_GLOBAL_STATIC`?

Inline variables are safer than static globals. Compiler and linker
guarantee that there will be just one definition.

`Q_GLOBAL_STATIC` still provides lazy initialization. So inline
variables are not a full replacement. Any big globals that aren't
necessarily used should be gated by lazy initialization to avoid
constructing them unnecessarily.


## Polymorphic lambdas

What is it? It has auto as its parameter type. So the same lambda can
be used with multiple invocations with parameters of different types.

Most common use is just for brevity. It gives you perfect forwarding
as well, if you use auto && as the type.

But these are not API visible, just perhaps useful inside the
implementation.


## Structured bindings

QRect and QPoint might be possible candidates. But there will not be
many that this makes sense for.

Some of these will already be aggregates and work automatically. But
perhaps they for example have user-defined constructors and so don't
fulfill the requirements of that.


## Language attributes

There are macros for many standard attributes, like nodiscard,
deprecated, fallthrough, likely and unlikely.

When is the right point to remove this macros and use the attributes
directly? When all compilers support it. Although that causes pain
when backporting to older branches.

That applies to all language features, though. Some backporting is
really hairy, like converting if constexpr solutions back to template
specializations.


## Modules (C++20)

Properly modularizing Qt is going to be a huge undertaking. There
should be some prototyping done by an energetic volunteer.

There are rumors that moc generated code leads to some issues here.

How will `QT_CONFIG()` macros work together with modules? Every
permutation would need to be shipped as a separate module. But they
are going to be constant within a built Qt. Not something the user of
the library can change.

Modules are not supported by build systems (including qmake and CMake)
yet. CMake developer Kitware is working on it, though.


## Coroutines (C++20)

QDialog::call/exec() are already coroutines, but stackful ones. So
converting to them stackless is not really possible. But there might
be better candidates in networking or elsewhere with callbacks.

Standard coroutines are quite cumbersome to use. Would we use an
external helper library with that or would Qt provide their own helper
for coroutines? Having Qt-friendly coroutine helpers would be nice.

Test data supplying is currently a huge matrix of QVariants and is
actually a performance bottleneck for our tests. Using generators for
these might be helpful? They are not going to make a difference
compared to a good hand-written generator. So the performance issues
might be fixed with other approaches.


# Library

Contributions to any of these would be welcome.


## std::any

std::any is like a QVariant that does not need registration.

Could there be conversions between QVariant and std::any? Ville is
skeptical about how to do that. Olivier suggested adding support for
conversion from std::any to QVariant into QMetatype. But can that be
done with just a reference to `std::type_info`?

std::any is a replacement for void\*. It knows the type that it holds.


## std::filesystem

Giuseppe: Should be use std::filesystem::path types consistently in
our APIs instead of QString? Ville: There should be a prototype patch
to see how big the effect is. I'm concerned that the impact would be
too big.

Is std::filesystem::path API stable enough? Standard committee cares
about API stability a lot, so that's not a worry. Although some want a
new version of the API that uses std::expected.


## Parallel STL algorithms

We could allow parallel execution tags in our API to let users ask for
use of parallel algorithms.

But what are the places in Qt API that actually need these? More data
analysis stuff (if developed) would find it helpful. But often users
get to choose their own algorithms and so can use parallel algorithms
without our containers needing to know about it.

If a parallel STL implementation is not available, falling back to
single-threaded implementation is always an option. So support could
be utilized only when available and not demanded from all platforms.
Or the platfrom support can be a shim that still always processes
everything without parallelism.


## `std::unique_ptr`

Better support for `std::unique_ptr` for Qt APIs?

A patch for more explicit ownership for QObject hierarchy has been
suggested in the past. Maybe out of scope for this session.
`std::unique_ptr` is not new in C++17.


## std::optional

Would it be worth changing API to return std::optionals instead of
bool output parameters? It would be a big source-incompatible change.


## `std::string_view`

Do we want to use `std::string_view`? Or do we need a QByteArrayView?
In order to match QByteArray API?

Will QByteArray still be for string data in Qt 6? That's a topic for
tomorrows session.

QByteArray has some API that expects the contents to be string-like.
Unfortunately, because they don't really belong there. QByteArray's
future should be clarified before making decisions about these can be
made.


## std::format (C++20)

Not available to us yet. And will work with `std::basic_string` only
pretty much. Not with QString.


# Co-operation with compiler vendors

Ville has talked to INTEGRITY multiple times. Technically they can
provide a C++17 compatible compiler due to using IDG frontend. They
haven't provided a timeline when that is actually released.

Embedded (and other) platforms that don't provide C++17 launch will be
initially dropped from being supported. They will be added later once
their compilers catch up.

QNX has gcc-based compiler so they should also be able to update their
systems.


# Testing

Testlib feels old and unfriendly. Reflection is the real killer
feature for nice testing. It would allow much less macro use and other
boilerplate. It's also the solution for everything else.


# Getting rid of moc

Reflection should also replace moc at some point.

Andrew (one of the reflection proposal authors) is working on
something very moc-like and would like feedback from the Qt community.
So far he has not gotten any. People who know our metaobject system
well should engage with standard committee members so that the final
reflection solution will serve us well. Ville Voutilainen is one
possible contact point in addition to Andrew Sutton.


# Replacing conditional compilation flags with if constexpr

if constexpr demands that all branches are valid. Other branch can
only not compile when it is inside a template.

Conditional compilation still needs the preprocessor, because if a
feature is disabled, the branch using it would not be valid code.


# Minimum compiler versions for 6.0

Lars had a proposal on the mailing list and there has been no
opposition.

The set of minimum versions would be:

-   GCC 9
-   Clang 9
-   Apple Clang 11 (Clang 9)
-   MSVC 2019

Thiago would like it to be a bit more conservative. But when 6.0 comes
out, GCC 9 will be one and a half years old. So it's not bleeding
edge. 18 months old compilers should be fine, but probably not much
newer than that.

Qt 6 will require C++17. So compiler will be need to switched to C++17
mode. But users might still be able to have codebases that only use
C++11, since not much API will necessarily require C++17 features to
use. So codebases with compatibility for older language versions (in
other builds) should be largely possible.



Very useful for our containers.


## Fold expressions

Shortcut for handling parameter packs of vadiadic templates. No need
to write recursive template helpers.


## Inline variable

Volker: What is the impact of using inline variables to static data
initialization? How do we deal with `Q_GLOBAL_STATIC`?

Inline variables are safer than static globals. Compiler and linker
guarantee that there will be just one definition.

`Q_GLOBAL_STATIC` still provides lazy initialization. So inline
variables are not a full replacement. Any big globals that aren't
necessarily used should be gated by lazy initialization to avoid
constructing them unnecessarily.


## Polymorphic lambdas

What is it? It has auto as its parameter type. So the same lambda can
be used with multiple invocations with parameters of different types.

Most common use is just for brevity. It gives you perfect forwarding
as well, if you use auto && as the type.

But these are not API visible, just perhaps useful inside the
implementation.


## Structured bindings

QRect and QPoint might be possible candidates. But there will not be
many that this makes sense for.

Some of these will already be aggregates and work automatically. But
perhaps they for example have user-defined constructors and so don't
fulfill the requirements of that.


## Language attributes

There are macros for many standard attributes, like nodiscard,
deprecated, fallthrough, likely and unlikely.

When is the right point to remove this macros and use the attributes
directly? When all compilers support it. Although that causes pain
when backporting to older branches.

That applies to all language features, though. Some backporting is
really hairy, like converting if constexpr solutions back to template
specializations.


## Modules (C++20)

Properly modularizing Qt is going to be a huge undertaking. There
should be some prototyping done by an energetic volunteer.

There are rumors that moc generated code leads to some issues here.

How will `QT_CONFIG()` macros work together with modules? Every
permutation would need to be shipped as a separate module. But they
are going to be constant within a built Qt. Not something the user of
the library can change.

Modules are not supported by build systems (including qmake and CMake)
yet. CMake developer Kitware is working on it, though.


## Coroutines (C++20)

QDialog::call/exec() are already coroutines, but stackful ones. So
converting to them stackless is not really possible. But there might
be better candidates in networking or elsewhere with callbacks.

Standard coroutines are quite cumbersome to use. Would we use an
external helper library with that or would Qt provide their own helper
for coroutines? Having Qt-friendly coroutine helpers would be nice.

Test data supplying is currently a huge matrix of QVariants and is
actually a performance bottleneck for our tests. Using generators for
these might be helpful? They are not going to make a difference
compared to a good hand-written generator. So the performance issues
might be fixed with other approaches.


# Library

Contributions to any of these would be welcome.


## std::any

std::any is like a QVariant that does not need registration.

Could there be conversions between QVariant and std::any? Ville is
skeptical about how to do that. Olivier suggested adding support for
conversion from std::any to QVariant into QMetatype. But can that be
done with just a reference to `std::type_info`?

std::any is a replacement for void\*. It knows the type that it holds.


## std::filesystem

Giuseppe: Should be use std::filesystem::path types consistently in
our APIs instead of QString? Ville: There should be a prototype patch
to see how big the effect is. I'm concerned that the impact would be
too big.

Is std::filesystem::path API stable enough? Standard committee cares
about API stability a lot, so that's not a worry. Although some want a
new version of the API that uses std::expected.


## Parallel STL algorithms

We could allow parallel execution tags in our API to let users ask for
use of parallel algorithms.

But what are the places in Qt API that actually need these? More data
analysis stuff (if developed) would find it helpful. But often users
get to choose their own algorithms and so can use parallel algorithms
without our containers needing to know about it.

If a parallel STL implementation is not available, falling back to
single-threaded implementation is always an option. So support could
be utilized only when available and not demanded from all platforms.
Or the platfrom support can be a shim that still always processes
everything without parallelism.


## `std::unique_ptr`

Better support for `std::unique_ptr` for Qt APIs?

A patch for more explicit ownership for QObject hierarchy has been
suggested in the past. Maybe out of scope for this session.
`std::unique_ptr` is not new in C++17.


## std::optional

Would it be worth changing API to return std::optionals instead of
bool output parameters? It would be a big source-incompatible change.


## `std::string_view`

Do we want to use `std::string_view`? Or do we need a QByteArrayView?
In order to match QByteArray API?

Will QByteArray still be for string data in Qt 6? That's a topic for
tomorrows session.

QByteArray has some API that expects the contents to be string-like.
Unfortunately, because they don't really belong there. QByteArray's
future should be clarified before making decisions about these can be
made.


## std::format (C++20)

Not available to us yet. And will work with `std::basic_string` only
pretty much. Not with QString.


# Co-operation with compiler vendors

Ville has talked to INTEGRITY multiple times. Technically they can
provide a C++17 compatible compiler due to using IDG frontend. They
haven't provided a timeline when that is actually released.

Embedded (and other) platforms that don't provide C++17 launch will be
initially dropped from being supported. They will be added later once
their compilers catch up.

QNX has gcc-based compiler so they should also be able to update their
systems.


# Testing

Testlib feels old and unfriendly. Reflection is the real killer
feature for nice testing. It would allow much less macro use and other
boilerplate. It's also the solution for everything else.


# Getting rid of moc

Reflection should also replace moc at some point.

Andrew (one of the reflection proposal authors) is working on
something very moc-like and would like feedback from the Qt community.
So far he has not gotten any. People who know our metaobject system
well should engage with standard committee members so that the final
reflection solution will serve us well. Ville Voutilainen is one
possible contact point in addition to Andrew Sutton.


# Replacing conditional compilation flags with if constexpr

if constexpr demands that all branches are valid. Other branch can
only not compile when it is inside a template.

Conditional compilation still needs the preprocessor, because if a
feature is disabled, the branch using it would not be valid code.


# Minimum compiler versions for 6.0

Lars had a proposal on the mailing list and there has been no
opposition.

The set of minimum versions would be:

-   GCC 9
-   Clang 9
-   Apple Clang 11 (Clang 9)
-   MSVC 2019

Thiago would like it to be a bit more conservative. But when 6.0 comes
out, GCC 9 will be one and a half years old. So it's not bleeding
edge. 18 months old compilers should be fine, but probably not much
newer than that.

Qt 6 will require C++17. So compiler will be need to switched to C++17
mode. But users might still be able to have codebases that only use
C++11, since not much API will necessarily require C++17 features to
use. So codebases with compatibility for older language versions (in
other builds) should be largely possible.

-- 
Kari


More information about the Development mailing list