diff options
-rw-r--r-- | src/corelib/tools/qsharedpointer.cpp | 51 | ||||
-rw-r--r-- | src/corelib/tools/qsharedpointer_impl.h | 42 | ||||
-rw-r--r-- | tests/auto/corelib/tools/qsharedpointer/tst_qsharedpointer.cpp | 55 |
3 files changed, 148 insertions, 0 deletions
diff --git a/src/corelib/tools/qsharedpointer.cpp b/src/corelib/tools/qsharedpointer.cpp index 62b76c5bb7..0aedf4c6d6 100644 --- a/src/corelib/tools/qsharedpointer.cpp +++ b/src/corelib/tools/qsharedpointer.cpp @@ -1300,6 +1300,57 @@ */ /*! + \fn template <class X, class T> std::shared_ptr<X> qSharedPointerObjectCast(const std::shared_ptr<T> &src) + \relates QSharedPointer + \since 5.14 + + Returns a shared pointer to the pointer held by \a src, using a + \l qobject_cast() to type \tt X to obtain an internal pointer of the + appropriate type. If the \tt qobject_cast fails, the object + returned will be null. + + Note that \tt X must have the same cv-qualifiers (\tt const and + \tt volatile) that \tt T has, or the code will fail to + compile. Use const_pointer_cast to cast away the constness. +*/ + +/*! + \fn template <class X, class T> std::shared_ptr<X> qobject_pointer_cast(const std::shared_ptr<T> &src) + \relates QSharedPointer + \since 5.14 + + Same as qSharedPointerObjectCast(). This function is provided for STL + compatibility. +*/ + +/*! + \fn template <class X, class T> std::shared_ptr<X> qSharedPointerObjectCast(std::shared_ptr<T> &&src) + \relates QSharedPointer + \since 5.14 + + Returns a shared pointer to the pointer held by \a src, using a + \l qobject_cast() to type \tt X to obtain an internal pointer of the + appropriate type. + + If the \tt qobject_cast succeeds, the function will return a valid shared + pointer, and \a src is reset to null. If the \tt qobject_cast fails, the + object returned will be null, and \a src will not be modified. + + Note that \tt X must have the same cv-qualifiers (\tt const and + \tt volatile) that \tt T has, or the code will fail to + compile. Use const_pointer_cast to cast away the constness. +*/ + +/*! + \fn template <class X, class T> std::shared_ptr<X> qobject_pointer_cast(std::shared_ptr<T> &&src) + \relates QSharedPointer + \since 5.14 + + Same as qSharedPointerObjectCast(). This function is provided for STL + compatibility. +*/ + +/*! \fn template <class X> template <class T> QSharedPointer<X> qSharedPointerObjectCast(const QWeakPointer<T> &src) \relates QSharedPointer \relates QWeakPointer diff --git a/src/corelib/tools/qsharedpointer_impl.h b/src/corelib/tools/qsharedpointer_impl.h index 81d8dcd839..0851121ff2 100644 --- a/src/corelib/tools/qsharedpointer_impl.h +++ b/src/corelib/tools/qsharedpointer_impl.h @@ -67,6 +67,8 @@ QT_END_NAMESPACE #endif #include <QtCore/qhashfunctions.h> +#include <memory> + QT_BEGIN_NAMESPACE @@ -996,6 +998,46 @@ qSharedPointerFromVariant(const QVariant &variant) return qSharedPointerObjectCast<T>(QtSharedPointer::sharedPointerFromVariant_internal(variant)); } +// std::shared_ptr helpers + +template <typename X, class T> +std::shared_ptr<X> qobject_pointer_cast(const std::shared_ptr<T> &src) +{ + using element_type = typename std::shared_ptr<X>::element_type; + return std::shared_ptr<X>(src, qobject_cast<element_type *>(src.get())); +} + +template <typename X, class T> +std::shared_ptr<X> qobject_pointer_cast(std::shared_ptr<T> &&src) +{ + using element_type = typename std::shared_ptr<X>::element_type; + auto castResult = qobject_cast<element_type *>(src.get()); + if (castResult) { + auto result = std::shared_ptr<X>(std::move(src), castResult); +#if __cplusplus <= 201703L + // C++2a's move aliasing constructor will leave src empty. + // Before C++2a we don't really know if the compiler has support for it. + // The move aliasing constructor is the resolution for LWG2996, + // which does not impose a feature-testing macro. So: clear src. + src.reset(); +#endif + return result; + } + return std::shared_ptr<X>(); +} + +template <typename X, class T> +std::shared_ptr<X> qSharedPointerObjectCast(const std::shared_ptr<T> &src) +{ + return qobject_pointer_cast<X>(src); +} + +template <typename X, class T> +std::shared_ptr<X> qSharedPointerObjectCast(std::shared_ptr<T> &&src) +{ + return qobject_pointer_cast<X>(std::move(src)); +} + #endif template<typename T> Q_DECLARE_TYPEINFO_BODY(QWeakPointer<T>, Q_MOVABLE_TYPE); diff --git a/tests/auto/corelib/tools/qsharedpointer/tst_qsharedpointer.cpp b/tests/auto/corelib/tools/qsharedpointer/tst_qsharedpointer.cpp index 19b2aa02f3..3e87a506bf 100644 --- a/tests/auto/corelib/tools/qsharedpointer/tst_qsharedpointer.cpp +++ b/tests/auto/corelib/tools/qsharedpointer/tst_qsharedpointer.cpp @@ -78,6 +78,7 @@ private slots: void sharedPointerFromQObjectWithWeak(); void weakQObjectFromSharedPointer(); void objectCast(); + void objectCastStdSharedPtr(); void differentPointers(); void virtualBaseDifferentPointers(); #ifndef QTEST_NO_RTTI @@ -1113,6 +1114,60 @@ void tst_QSharedPointer::objectCast() safetyCheck(); } + +void tst_QSharedPointer::objectCastStdSharedPtr() +{ + { + OtherObject *data = new OtherObject; + std::shared_ptr<QObject> baseptr = std::shared_ptr<QObject>(data); + QVERIFY(baseptr.get() == data); + + // perform successful object cast + std::shared_ptr<OtherObject> ptr = qobject_pointer_cast<OtherObject>(baseptr); + QVERIFY(ptr.get()); + QVERIFY(ptr.get() == data); + + QVERIFY(baseptr.get() == data); + } + + { + OtherObject *data = new OtherObject; + std::shared_ptr<QObject> baseptr = std::shared_ptr<QObject>(data); + QVERIFY(baseptr.get() == data); + + // perform successful object cast + std::shared_ptr<OtherObject> ptr = qobject_pointer_cast<OtherObject>(std::move(baseptr)); + QVERIFY(ptr.get()); + QVERIFY(ptr.get() == data); + + QVERIFY(!baseptr.get()); + } + + { + QObject *data = new QObject; + std::shared_ptr<QObject> baseptr = std::shared_ptr<QObject>(data); + QVERIFY(baseptr.get() == data); + + // perform unsuccessful object cast + std::shared_ptr<OtherObject> ptr = qobject_pointer_cast<OtherObject>(baseptr); + QVERIFY(!ptr.get()); + + QVERIFY(baseptr.get() == data); + } + + { + QObject *data = new QObject; + std::shared_ptr<QObject> baseptr = std::shared_ptr<QObject>(data); + QVERIFY(baseptr.get() == data); + + // perform unsuccessful object cast + std::shared_ptr<OtherObject> ptr = qobject_pointer_cast<OtherObject>(std::move(baseptr)); + QVERIFY(!ptr.get()); + + QVERIFY(baseptr.get() == data); + } +} + void tst_QSharedPointer::differentPointers() { { |