QWeakPointer: use an alternative work-round for internalData() users

The previous work-around fails, probably because of
cross-dependencies. E.g. we have this in QtScXml:

In file included from /home/qt/work/install/include/QtCore/qsharedpointer.h:48:0,
                  from ../../src/scxml/qscxmltabledata_p.h:55,
                  from ../../src/scxml/qscxmltabledata.cpp:40:
 /home/qt/work/install/include/QtCore/qsharedpointer_impl.h:687:12: error: ‘QPointer’ does not name a type; did you mean ‘pointer’?
      friend QPointer<X>
             ^~~~~~~~
             pointer
 /home/qt/work/install/include/QtCore/qsharedpointer_impl.h:689:23: error: ‘QSmartPointerConvertFunctor’ in namespace ‘QtPrivate’ does not name a template type
      friend QtPrivate::QSmartPointerConvertFunctor<QWeakPointer>;
                        ^~~~~~~~~~~~~~~~~~~~~~~~~~~

To fix, grand friendship only to a non-template class with a templated
static method that returns internalData(). This fixes most users,
except in qmetatype.h, which does not include qsharedpointer.h. In
order to use the non-template class in there, we need to delay its
name lookup to instantiation time. We do this by artificially making
it a dependent name, by using a class template that inherits from
our befrieded class.

Change-Id: I12b427f1fe9503df819ea5436d780972d6402e68
Reviewed-by: Ville Voutilainen <ville.voutilainen@qt.io>
Marc Mutz 2019-06-06 12:52:15 +02:00
parent fafae936a6
commit 242bc539ab
3 changed files with 25 additions and 13 deletions

View File

@ -1715,12 +1715,17 @@ namespace QtPrivate {
}
};
// hack to delay name lookup to instantiation time by making
// EnableInternalData a dependent name:
template <typename T>
struct EnableInternalDataWrap;
template<typename T>
struct QSmartPointerConvertFunctor<QWeakPointer<T> >
{
QObject* operator()(const QWeakPointer<T> &p) const
{
return p.internalData();
return QtPrivate::EnableInternalDataWrap<T>::internalData(p);
}
};
}

View File

@ -143,7 +143,8 @@ template<typename T>
QPointer<T>
qPointerFromVariant(const QVariant &variant)
{
return QPointer<T>(qobject_cast<T*>(QtSharedPointer::weakPointerFromVariant_internal(variant).internalData()));
const auto wp = QtSharedPointer::weakPointerFromVariant_internal(variant);
return QPointer<T>{qobject_cast<T*>(QtPrivate::EnableInternalData::internalData(wp))};
}
template <class T>

View File

@ -107,6 +107,10 @@ template <class X, class T>
QSharedPointer<X> qSharedPointerObjectCast(const QSharedPointer<T> &ptr);
#endif
namespace QtPrivate {
struct EnableInternalData;
}
namespace QtSharedPointer {
template <class T> class ExternalRefCount;
@ -672,21 +676,12 @@ public:
#endif
private:
friend struct QtPrivate::EnableInternalData;
#if defined(Q_NO_TEMPLATE_FRIENDS)
public:
#else
template <class X> friend class QSharedPointer;
template <class X> friend class QPointer;
# ifndef QT_NO_QOBJECT
template<typename X>
friend QWeakPointer<typename std::enable_if<QtPrivate::IsPointerToTypeDerivedFromQObject<X*>::Value, X>::type>
qWeakPointerFromVariant(const QVariant &variant);
# endif
template<typename X>
friend QPointer<X>
qPointerFromVariant(const QVariant &variant);
friend QtPrivate::QSmartPointerConvertFunctor<QWeakPointer>;
#endif
template <class X>
@ -721,6 +716,17 @@ public:
T *value;
};
namespace QtPrivate {
struct EnableInternalData {
template <typename T>
static T *internalData(const QWeakPointer<T> &p) noexcept { return p.internalData(); }
};
// hack to delay name lookup to instantiation time by making
// EnableInternalData a dependent name:
template <typename T>
struct EnableInternalDataWrap : EnableInternalData {};
}
template <class T>
class QEnableSharedFromThis
{
@ -996,7 +1002,7 @@ template<typename T>
QWeakPointer<typename std::enable_if<QtPrivate::IsPointerToTypeDerivedFromQObject<T*>::Value, T>::type>
qWeakPointerFromVariant(const QVariant &variant)
{
return QWeakPointer<T>(qobject_cast<T*>(QtSharedPointer::weakPointerFromVariant_internal(variant).internalData()));
return QWeakPointer<T>(qobject_cast<T*>(QtPrivate::EnableInternalData::internalData(QtSharedPointer::weakPointerFromVariant_internal(variant))));
}
template<typename T>
QSharedPointer<typename std::enable_if<QtPrivate::IsPointerToTypeDerivedFromQObject<T*>::Value, T>::type>