<QtTypeTraits> - Qt Type Traits
Functionality for type traits and transformations. More...
Header: | #include <QtTypeTraits> |
Since: | Qt 6.5 |
Functions
typename std::add_const<T>::type & | qAsConst(T &t) |
void | qAsConst(const T &&t) |
T | qExchange(T &obj, U &&newValue) |
std::underlying_type_t<Enum> | qToUnderlying(Enum e) |
Function Documentation
[constexpr]
template <typename T> typename std::add_const<T>::type &qAsConst(T &t)
Returns t cast to const T
.
This function is a Qt implementation of C++17's std::as_const(), a cast function like std::move(). But while std::move() turns lvalues into rvalues, this function turns non-const lvalues into const lvalues. Like std::as_const(), it doesn't work on rvalues, because it cannot be efficiently implemented for rvalues without leaving dangling references.
Its main use in Qt is to prevent implicitly-shared Qt containers from detaching:
QString s = ...; for (QChar ch : s) // detaches 's' (performs a deep-copy if 's' was shared) process(ch); for (QChar ch : qAsConst(s)) // ok, no detach attempt process(ch);
Of course, in this case, you could (and probably should) have declared s
as const
in the first place:
but often that is not easily possible.
It is important to note that qAsConst() does not copy its argument, it just performs a const_cast<const T&>(t)
. This is also the reason why it is designed to fail for rvalues: The returned reference would go stale too soon. So while this works (but detaches the returned object):
for (QChar ch : funcReturningQString()) process(ch); // OK, the returned object is kept alive for the loop's duration
this would not:
for (QChar ch : qAsConst(funcReturningQString())) process(ch); // ERROR: ch is copied from deleted memory
To prevent this construct from compiling (and failing at runtime), qAsConst() has a second, deleted, overload which binds to rvalues.
template <typename T> void qAsConst(const T &&t)
This is an overloaded function.
This overload is deleted to prevent a dangling reference in code like
for (QChar ch : qAsConst(funcReturningQString())) process(ch); // ERROR: ch is copied from deleted memory
[constexpr]
template <typename T, typename U> 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.
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.
[constexpr, 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.
© 2024 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.