summaryrefslogtreecommitdiffstats
path: root/src/corelib/global
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/global')
-rw-r--r--src/corelib/global/qforeach.h1
-rw-r--r--src/corelib/global/qglobal.cpp96
-rw-r--r--src/corelib/global/qglobal.h18
-rw-r--r--src/corelib/global/qttypetraits.h19
-rw-r--r--src/corelib/global/qttypetraits.qdoc96
5 files changed, 116 insertions, 114 deletions
diff --git a/src/corelib/global/qforeach.h b/src/corelib/global/qforeach.h
index 80d0c41aa2..e8396c4fb0 100644
--- a/src/corelib/global/qforeach.h
+++ b/src/corelib/global/qforeach.h
@@ -7,6 +7,7 @@
#include <QtCore/qglobal.h>
#include <QtCore/qtdeprecationmarkers.h>
+#include <QtCore/qttypetraits.h>
QT_BEGIN_NAMESPACE
diff --git a/src/corelib/global/qglobal.cpp b/src/corelib/global/qglobal.cpp
index 7077efb662..e444755f1b 100644
--- a/src/corelib/global/qglobal.cpp
+++ b/src/corelib/global/qglobal.cpp
@@ -228,102 +228,6 @@ void qAbort()
// strftime() -- not used (except in tests)
/*!
- \fn template <typename T> typename std::add_const<T>::type &qAsConst(T &t)
- \relates <QtGlobal>
- \since 5.7
-
- Returns \a t cast to \c{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:
- \snippet code/src_corelib_global_qglobal.cpp as-const-0
-
- Of course, in this case, you could (and probably should) have declared
- \c s as \c const in the first place:
- \snippet code/src_corelib_global_qglobal.cpp as-const-1
- but often that is not easily possible.
-
- It is important to note that qAsConst() does not copy its argument,
- it just performs a \c{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):
- \snippet code/src_corelib_global_qglobal.cpp as-const-2
-
- this would not:
- \snippet code/src_corelib_global_qglobal.cpp as-const-3
-
- To prevent this construct from compiling (and failing at runtime), qAsConst() has
- a second, deleted, overload which binds to rvalues.
-*/
-
-/*!
- \fn template <typename T> void qAsConst(const T &&t)
- \relates <QtGlobal>
- \since 5.7
- \overload
-
- This overload is deleted to prevent a dangling reference in code like
- \snippet code/src_corelib_global_qglobal.cpp as-const-4
-*/
-
-/*!
- \fn template <typename T, typename U = T> T qExchange(T &obj, U &&newValue)
- \relates <QtGlobal>
- \since 5.14
-
- Replaces the value of \a obj with \a newValue and returns the old value of \a obj.
-
- This is Qt's implementation of std::exchange(). It differs from std::exchange()
- only in that it is \c constexpr already in C++14, and available on all supported
- compilers.
-
- Here is how to use qExchange() to implement move constructors:
- \code
- MyClass(MyClass &&other)
- : m_pointer{qExchange(other.m_pointer, nullptr)},
- m_int{qExchange(other.m_int, 0)},
- m_vector{std::move(other.m_vector)},
- ...
- \endcode
-
- 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:
- \code
- for (auto &e : qExchange(collection, {})
- doSomethingWith(e);
- \endcode
-
- Which is equivalent to the following, much more verbose code:
- \code
- {
- auto tmp = std::move(collection);
- collection = {}; // or collection.clear()
- for (auto &e : tmp)
- doSomethingWith(e);
- } // destroys 'tmp'
- \endcode
-
- 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.
-*/
-
-/*!
\macro Q_UNUSED(name)
\relates <QtGlobal>
diff --git a/src/corelib/global/qglobal.h b/src/corelib/global/qglobal.h
index 4e9e0609f1..ef42bc9d35 100644
--- a/src/corelib/global/qglobal.h
+++ b/src/corelib/global/qglobal.h
@@ -54,24 +54,6 @@ QT_BEGIN_NAMESPACE
# define Q_UNIMPLEMENTED() qWarning("Unimplemented code.")
#endif
-
-// this adds const to non-const objects (like std::as_const)
-template <typename T>
-constexpr typename std::add_const<T>::type &qAsConst(T &t) noexcept { return t; }
-// prevent rvalue arguments:
-template <typename T>
-void qAsConst(const T &&) = delete;
-
-// like std::exchange
-template <typename T, typename U = T>
-constexpr T qExchange(T &t, U &&newValue)
-noexcept(std::conjunction_v<std::is_nothrow_move_constructible<T>, std::is_nothrow_assignable<T &, U>>)
-{
- T old = std::move(t);
- t = std::forward<U>(newValue);
- return old;
-}
-
QT_END_NAMESPACE
// We need to keep QTypeInfo, QSysInfo, QFlags, qDebug & family in qglobal.h for compatibility with Qt 4.
diff --git a/src/corelib/global/qttypetraits.h b/src/corelib/global/qttypetraits.h
index 02921f2b64..1832a1a734 100644
--- a/src/corelib/global/qttypetraits.h
+++ b/src/corelib/global/qttypetraits.h
@@ -7,6 +7,7 @@
#include <QtCore/qtconfigmacros.h>
#include <type_traits>
+#include <utility>
#if 0
#pragma qt_class(QtTypeTraits)
@@ -22,6 +23,24 @@ constexpr std::underlying_type_t<Enum> qToUnderlying(Enum e) noexcept
return static_cast<std::underlying_type_t<Enum>>(e);
}
+// this adds const to non-const objects (like std::as_const)
+template <typename T>
+constexpr typename std::add_const<T>::type &qAsConst(T &t) noexcept { return t; }
+// prevent rvalue arguments:
+template <typename T>
+void qAsConst(const T &&) = delete;
+
+// like std::exchange
+template <typename T, typename U = T>
+constexpr T qExchange(T &t, U &&newValue)
+noexcept(std::conjunction_v<std::is_nothrow_move_constructible<T>,
+ std::is_nothrow_assignable<T &, U>>)
+{
+ T old = std::move(t);
+ t = std::forward<U>(newValue);
+ return old;
+}
+
QT_END_NAMESPACE
#endif // QTTYPETRAITS_H
diff --git a/src/corelib/global/qttypetraits.qdoc b/src/corelib/global/qttypetraits.qdoc
index 5c87f81a8b..6bb1ceba2c 100644
--- a/src/corelib/global/qttypetraits.qdoc
+++ b/src/corelib/global/qttypetraits.qdoc
@@ -9,3 +9,99 @@
Converts the enumerator \a e to the equivalent value expressed in its
enumeration's underlying type.
*/
+
+/*!
+ \fn template <typename T> typename std::add_const<T>::type &qAsConst(T &t)
+ \relates <QtTypeTraits>
+ \since 5.7
+
+ Returns \a t cast to \c{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:
+ \snippet code/src_corelib_global_qglobal.cpp as-const-0
+
+ Of course, in this case, you could (and probably should) have declared
+ \c s as \c const in the first place:
+ \snippet code/src_corelib_global_qglobal.cpp as-const-1
+ but often that is not easily possible.
+
+ It is important to note that qAsConst() does not copy its argument,
+ it just performs a \c{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):
+ \snippet code/src_corelib_global_qglobal.cpp as-const-2
+
+ this would not:
+ \snippet code/src_corelib_global_qglobal.cpp as-const-3
+
+ To prevent this construct from compiling (and failing at runtime), qAsConst() has
+ a second, deleted, overload which binds to rvalues.
+*/
+
+/*!
+ \fn template <typename T> void qAsConst(const T &&t)
+ \relates <QtTypeTraits>
+ \since 5.7
+ \overload
+
+ This overload is deleted to prevent a dangling reference in code like
+ \snippet code/src_corelib_global_qglobal.cpp as-const-4
+*/
+
+/*!
+ \fn template <typename T, typename U = T> T qExchange(T &obj, U &&newValue)
+ \relates <QtTypeTraits>
+ \since 5.14
+
+ Replaces the value of \a obj with \a newValue and returns the old value of \a obj.
+
+ This is Qt's implementation of std::exchange(). It differs from std::exchange()
+ only in that it is \c constexpr already in C++14, and available on all supported
+ compilers.
+
+ Here is how to use qExchange() to implement move constructors:
+ \code
+ MyClass(MyClass &&other)
+ : m_pointer{qExchange(other.m_pointer, nullptr)},
+ m_int{qExchange(other.m_int, 0)},
+ m_vector{std::move(other.m_vector)},
+ ...
+ \endcode
+
+ 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:
+ \code
+ for (auto &e : qExchange(collection, {})
+ doSomethingWith(e);
+ \endcode
+
+ Which is equivalent to the following, much more verbose code:
+ \code
+ {
+ auto tmp = std::move(collection);
+ collection = {}; // or collection.clear()
+ for (auto &e : tmp)
+ doSomethingWith(e);
+ } // destroys 'tmp'
+ \endcode
+
+ 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.
+*/