diff options
author | Milian Wolff <milian.wolff@kdab.com> | 2019-09-05 09:58:30 +0200 |
---|---|---|
committer | Milian Wolff <milian.wolff@kdab.com> | 2019-10-11 16:53:23 +0200 |
commit | 014d7ac65417ed9b5ffb85cca24d16564ff5005a (patch) | |
tree | 3eb24e42350bdbbf731d9300672a7ccdf50b2378 /src | |
parent | 472f5331ca8091b191944650d043a288dac7c3e8 (diff) |
Q{Shared,Weak}Pointer: Reduce overload sets in implicit conversions
Only allow implicit conversions when the types involved are compatible.
That means, only allow construction and copy assignment when the type
X* is convertible to type T*. This is done using SFINAE and the
std::is_convertible type trait, which makes the previous
QSHAREDPOINTER_VERIFY_AUTO_CAST obsolete.
This patch fixes compilation when a function is overloaded with
Q{Shared,Weak}Pointer of different, incompatible types. Previously, this
resulted in a compilation error due to an ambiguous overload.
Change-Id: I069d22f3582e69842f14284d4f27827326597ca2
Fixes: QTBUG-75222
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/corelib/tools/qsharedpointer_impl.h | 51 |
1 files changed, 20 insertions, 31 deletions
diff --git a/src/corelib/tools/qsharedpointer_impl.h b/src/corelib/tools/qsharedpointer_impl.h index bccf8c5740..f2158436fd 100644 --- a/src/corelib/tools/qsharedpointer_impl.h +++ b/src/corelib/tools/qsharedpointer_impl.h @@ -69,21 +69,6 @@ QT_END_NAMESPACE QT_BEGIN_NAMESPACE - -// Macro QSHAREDPOINTER_VERIFY_AUTO_CAST -// generates a compiler error if the following construct isn't valid: -// T *ptr1; -// X *ptr2 = ptr1; -// -#ifdef QT_NO_DEBUG -# define QSHAREDPOINTER_VERIFY_AUTO_CAST(T, X) qt_noop() -#else - -template<typename T> inline void qt_sharedpointer_cast_check(T *) { } -# define QSHAREDPOINTER_VERIFY_AUTO_CAST(T, X) \ - qt_sharedpointer_cast_check<T>(static_cast<X *>(0)) -#endif - // // forward declarations // @@ -293,6 +278,9 @@ template <class T> class QSharedPointer { typedef T *QSharedPointer:: *RestrictedBool; typedef QtSharedPointer::ExternalRefCountData Data; + template <typename X> + using IfCompatible = typename std::enable_if<std::is_convertible<X*, T*>::value, bool>::type; + public: typedef T Type; typedef T element_type; @@ -316,11 +304,11 @@ public: Q_DECL_CONSTEXPR QSharedPointer(std::nullptr_t) Q_DECL_NOTHROW : value(nullptr), d(nullptr) { } - template <class X> + template <class X, IfCompatible<X> = true> inline explicit QSharedPointer(X *ptr) : value(ptr) // noexcept { internalConstruct(ptr, QtSharedPointer::NormalDeleter()); } - template <class X, typename Deleter> + template <class X, typename Deleter, IfCompatible<X> = true> inline QSharedPointer(X *ptr, Deleter deleter) : value(ptr) // throws { internalConstruct(ptr, deleter); } @@ -349,7 +337,7 @@ public: return *this; } - template <class X> + template <class X, IfCompatible<X> = true> QSharedPointer(QSharedPointer<X> &&other) Q_DECL_NOTHROW : value(other.value), d(other.d) { @@ -357,7 +345,7 @@ public: other.value = nullptr; } - template <class X> + template <class X, IfCompatible<X> = true> QSharedPointer &operator=(QSharedPointer<X> &&other) Q_DECL_NOTHROW { QSharedPointer moved(std::move(other)); @@ -367,11 +355,11 @@ public: #endif - template <class X> + template <class X, IfCompatible<X> = true> QSharedPointer(const QSharedPointer<X> &other) Q_DECL_NOTHROW : value(other.value), d(other.d) { if (d) ref(); } - template <class X> + template <class X, IfCompatible<X> = true> inline QSharedPointer &operator=(const QSharedPointer<X> &other) { QSharedPointer copy(other); @@ -379,11 +367,11 @@ public: return *this; } - template <class X> + template <class X, IfCompatible<X> = true> inline QSharedPointer(const QWeakPointer<X> &other) : value(nullptr), d(nullptr) { *this = other; } - template <class X> + template <class X, IfCompatible<X> = true> inline QSharedPointer<T> &operator=(const QWeakPointer<X> &other) { internalSet(other.d, other.value); return *this; } @@ -553,6 +541,8 @@ class QWeakPointer { typedef T *QWeakPointer:: *RestrictedBool; typedef QtSharedPointer::ExternalRefCountData Data; + template <typename X> + using IfCompatible = typename std::enable_if<std::is_convertible<X*, T*>::value, bool>::type; public: typedef T element_type; @@ -574,14 +564,14 @@ public: #ifndef QT_NO_QOBJECT // special constructor that is enabled only if X derives from QObject #if QT_DEPRECATED_SINCE(5, 0) - template <class X> + template <class X, IfCompatible<X> = true> QT_DEPRECATED inline QWeakPointer(X *ptr) : d(ptr ? Data::getAndRef(ptr) : nullptr), value(ptr) { } #endif #endif #if QT_DEPRECATED_SINCE(5, 0) - template <class X> + template <class X, IfCompatible<X> = true> QT_DEPRECATED inline QWeakPointer &operator=(X *ptr) { return *this = QWeakPointer(ptr); } #endif @@ -619,11 +609,11 @@ public: return *this; } - template <class X> + template <class X, IfCompatible<X> = true> inline QWeakPointer(const QWeakPointer<X> &o) : d(nullptr), value(nullptr) { *this = o; } - template <class X> + template <class X, IfCompatible<X> = true> inline QWeakPointer &operator=(const QWeakPointer<X> &o) { // conversion between X and T could require access to the virtual table @@ -640,14 +630,13 @@ public: bool operator!=(const QWeakPointer<X> &o) const Q_DECL_NOTHROW { return !(*this == o); } - template <class X> + template <class X, IfCompatible<X> = true> inline QWeakPointer(const QSharedPointer<X> &o) : d(nullptr), value(nullptr) { *this = o; } - template <class X> + template <class X, IfCompatible<X> = true> inline QWeakPointer &operator=(const QSharedPointer<X> &o) { - QSHAREDPOINTER_VERIFY_AUTO_CAST(T, X); // if you get an error in this line, the cast is invalid internalSet(o.d, o.data()); return *this; } @@ -684,7 +673,7 @@ public: { return *this = QWeakPointer<X>(ptr, true); } #ifndef QT_NO_QOBJECT - template <class X> + template <class X, IfCompatible<X> = true> inline QWeakPointer(X *ptr, bool) : d(ptr ? Data::getAndRef(ptr) : nullptr), value(ptr) { } #endif |