<QtTypeTraits> - Qt Type Traits

Functionality for type traits and transformations. More...

Header: #include <QtTypeTraits>
Since: Qt 6.5

Functions

T qExchange(T &obj, U &&newValue)
(since 6.2) std::underlying_type_t<Enum> qToUnderlying(Enum e)

Macros

(since 6.8) QT_NO_QASCONST
(since 6.6) QT_NO_QEXCHANGE

Detailed Description

Function Documentation

[constexpr noexcept(...)] template <typename T, typename U = T> T qExchange(T &obj, U &&newValue)

Replaces the value of obj with newValue and returns the old value of obj.

This is Qt's implementation of std::exchange(). It differs from std::exchange() only in that it is constexpr already before C++20 and noexcept already before C++23.

We strongly advise to use std::exchange() when you don't need the C++20 or C++23 variants. You can make qExchange() unavailable by defining the QT_NO_QEXCHANGE macro.

Here is how to use qExchange() to implement move constructors:

 MyClass(MyClass &&other)
   : m_pointer{qExchange(other.m_pointer, nullptr)},
     m_int{qExchange(other.m_int, 0)},
     m_vector{std::move(other.m_vector)},
     ...

For members of class type, we can use std::move(), as their move-constructor will do the right thing. But for scalar types such as raw pointers or integer type, move is the same as copy, which, particularly for pointers, is not what we expect. So, we cannot use std::move() for such types, but we can use std::exchange()/qExchange() to make sure the source object's member is already reset by the time we get to the initialization of our next data member, which might come in handy if the constructor exits with an exception.

Here is how to use qExchange() to write a loop that consumes the collection it iterates over:

 for (auto &e : qExchange(collection, {})
     doSomethingWith(e);

Which is equivalent to the following, much more verbose code:

 {
     auto tmp = std::move(collection);
     collection = {};                    // or collection.clear()
     for (auto &e : tmp)
         doSomethingWith(e);
 }                                       // destroys 'tmp'

This is perfectly safe, as the for-loop keeps the result of qExchange() alive for as long as the loop runs, saving the declaration of a temporary variable. Be aware, though, that qExchange() returns a non-const object, so Qt containers may detach.

Note: This function does not throw any exception when "std::conjunction_v<std::is_nothrow_move_constructible<T>, std::is_nothrow_assignable<T &, U>>" is true.

[constexpr noexcept, since 6.2] template <typename Enum> std::underlying_type_t<Enum> qToUnderlying(Enum e)

Converts the enumerator e to the equivalent value expressed in its enumeration's underlying type.

This function was introduced in Qt 6.2.

Macro Documentation

[since 6.8] QT_NO_QASCONST

Defining this macro removes the availability of the qAsConst() function.

This macro was introduced in Qt 6.8.

See also qAsConst.

[since 6.6] QT_NO_QEXCHANGE

Defining this macro removes the availability of the qExchange() function.

This macro was introduced in Qt 6.6.

See also qExchange.