From dff985140a9f31632ba6630ec3391be55051a7ac Mon Sep 17 00:00:00 2001 From: Ivan Solovev Date: Fri, 30 Sep 2022 13:12:42 +0200 Subject: Move qAsConst() and qExchange() to QtTypeTraits It's the least worst place we could think of. Add the qttypetraits.h include to qforeach, because otherwise the tests fail to build. Task-number: QTBUG-106154 Task-number: QTBUG-99313 Change-Id: I841f22e887f351146589377ec2376957e2adfd5e Reviewed-by: Thiago Macieira --- src/corelib/global/qglobal.cpp | 96 ------------------------------------------ 1 file changed, 96 deletions(-) (limited to 'src/corelib/global/qglobal.cpp') 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 @@ -227,102 +227,6 @@ void qAbort() // localtime() -- but not localtime_r(), which we use when threaded // strftime() -- not used (except in tests) -/*! - \fn template typename std::add_const::type &qAsConst(T &t) - \relates - \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(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 void qAsConst(const T &&t) - \relates - \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 T qExchange(T &obj, U &&newValue) - \relates - \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 -- cgit v1.2.3