Make it possible to use QObjectPrivate::connect in private code
In most QObjectPrivate-subclasses, the Q_DECLARE_PUBLIC macro is used in the private segment of the class declaration. In that case, the q_ptr becomes a private member of the private class, and then the QObjectPrivate::connect function can no longer be used, as it needs to access the d_ptr. Fix this by declaring QObjectPrivate, and the static-assert-helper, as friends of the class using the Q_DECLARE_PUBLIC macro. Adapt the QObject test by moving the Q_DECLARE_PUBLIC macro into the private section of the test-private, and add a compile test. Pick-to: 6.5 6.5.0 Change-Id: Ifc04be3b305221e138b1e08bb3a3838d871f4fcb Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Axel Spoerl <axel.spoerl@qt.io> Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
This commit is contained in:
parent
454dafb0e1
commit
4f02973e2f
@ -78,6 +78,13 @@ template <typename T> inline T *qGetPtrHelper(T *ptr) noexcept { return ptr; }
|
|||||||
template <typename Ptr> inline auto qGetPtrHelper(Ptr &ptr) noexcept -> decltype(ptr.get())
|
template <typename Ptr> inline auto qGetPtrHelper(Ptr &ptr) noexcept -> decltype(ptr.get())
|
||||||
{ static_assert(noexcept(ptr.get()), "Smart d pointers for Q_DECLARE_PRIVATE must have noexcept get()"); return ptr.get(); }
|
{ static_assert(noexcept(ptr.get()), "Smart d pointers for Q_DECLARE_PRIVATE must have noexcept get()"); return ptr.get(); }
|
||||||
|
|
||||||
|
class QObject;
|
||||||
|
class QObjectPrivate;
|
||||||
|
namespace QtPrivate {
|
||||||
|
template <typename ObjPrivate> void assertObjectType(QObjectPrivate *d);
|
||||||
|
inline const QObject *getQObject(const QObjectPrivate *d);
|
||||||
|
}
|
||||||
|
|
||||||
#define Q_DECLARE_PRIVATE(Class) \
|
#define Q_DECLARE_PRIVATE(Class) \
|
||||||
inline Class##Private* d_func() noexcept \
|
inline Class##Private* d_func() noexcept \
|
||||||
{ Q_CAST_IGNORE_ALIGN(return reinterpret_cast<Class##Private *>(qGetPtrHelper(d_ptr));) } \
|
{ Q_CAST_IGNORE_ALIGN(return reinterpret_cast<Class##Private *>(qGetPtrHelper(d_ptr));) } \
|
||||||
@ -95,7 +102,9 @@ template <typename Ptr> inline auto qGetPtrHelper(Ptr &ptr) noexcept -> decltype
|
|||||||
#define Q_DECLARE_PUBLIC(Class) \
|
#define Q_DECLARE_PUBLIC(Class) \
|
||||||
inline Class* q_func() noexcept { return static_cast<Class *>(q_ptr); } \
|
inline Class* q_func() noexcept { return static_cast<Class *>(q_ptr); } \
|
||||||
inline const Class* q_func() const noexcept { return static_cast<const Class *>(q_ptr); } \
|
inline const Class* q_func() const noexcept { return static_cast<const Class *>(q_ptr); } \
|
||||||
friend class Class;
|
friend class Class; \
|
||||||
|
friend const QObject *QtPrivate::getQObject(const QObjectPrivate *d); \
|
||||||
|
template <typename ObjPrivate> friend void QtPrivate::assertObjectType(QObjectPrivate *d);
|
||||||
|
|
||||||
#define Q_D(Class) Class##Private * const d = d_func()
|
#define Q_D(Class) Class##Private * const d = d_func()
|
||||||
#define Q_Q(Class) Class * const q = q_func()
|
#define Q_Q(Class) Class * const q = q_func()
|
||||||
|
@ -243,6 +243,7 @@ inline void QObjectPrivate::disconnectNotify(const QMetaMethod &signal)
|
|||||||
}
|
}
|
||||||
|
|
||||||
namespace QtPrivate {
|
namespace QtPrivate {
|
||||||
|
inline const QObject *getQObject(const QObjectPrivate *d) { return d->q_func(); }
|
||||||
|
|
||||||
template <typename Func>
|
template <typename Func>
|
||||||
struct FunctionStorageByValue
|
struct FunctionStorageByValue
|
||||||
@ -322,7 +323,7 @@ inline QMetaObject::Connection QObjectPrivate::connect(const typename QtPrivate:
|
|||||||
types = QtPrivate::ConnectionTypes<typename SignalType::Arguments>::types();
|
types = QtPrivate::ConnectionTypes<typename SignalType::Arguments>::types();
|
||||||
|
|
||||||
return QObject::connectImpl(sender, reinterpret_cast<void **>(&signal),
|
return QObject::connectImpl(sender, reinterpret_cast<void **>(&signal),
|
||||||
receiverPrivate->q_ptr, reinterpret_cast<void **>(&slot),
|
QtPrivate::getQObject(receiverPrivate), reinterpret_cast<void **>(&slot),
|
||||||
new QtPrivate::QPrivateSlotObject<Func2, typename QtPrivate::List_Left<typename SignalType::Arguments, SlotType::ArgumentCount>::Value,
|
new QtPrivate::QPrivateSlotObject<Func2, typename QtPrivate::List_Left<typename SignalType::Arguments, SlotType::ArgumentCount>::Value,
|
||||||
typename SignalType::ReturnType>(slot),
|
typename SignalType::ReturnType>(slot),
|
||||||
type, types, &SignalType::Object::staticMetaObject);
|
type, types, &SignalType::Object::staticMetaObject);
|
||||||
|
@ -5982,15 +5982,15 @@ class ConnectToPrivateSlotPrivate;
|
|||||||
|
|
||||||
class ConnectToPrivateSlot :public QObject {
|
class ConnectToPrivateSlot :public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
Q_DECLARE_PRIVATE(ConnectToPrivateSlot)
|
||||||
public:
|
public:
|
||||||
ConnectToPrivateSlot();
|
ConnectToPrivateSlot();
|
||||||
void test(SenderObject *obj1) ;
|
void test(SenderObject *obj1) ;
|
||||||
Q_DECLARE_PRIVATE(ConnectToPrivateSlot)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class ConnectToPrivateSlotPrivate : public QObjectPrivate {
|
class ConnectToPrivateSlotPrivate : public QObjectPrivate {
|
||||||
public:
|
|
||||||
Q_DECLARE_PUBLIC(ConnectToPrivateSlot)
|
Q_DECLARE_PUBLIC(ConnectToPrivateSlot)
|
||||||
|
public:
|
||||||
int receivedCount;
|
int receivedCount;
|
||||||
QVariant receivedValue;
|
QVariant receivedValue;
|
||||||
|
|
||||||
@ -6002,6 +6002,8 @@ public:
|
|||||||
receivedCount++;
|
receivedCount++;
|
||||||
receivedValue = v;
|
receivedValue = v;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void testFromPrivate(SenderObject *obj);
|
||||||
};
|
};
|
||||||
|
|
||||||
ConnectToPrivateSlot::ConnectToPrivateSlot(): QObject(*new ConnectToPrivateSlotPrivate) {}
|
ConnectToPrivateSlot::ConnectToPrivateSlot(): QObject(*new ConnectToPrivateSlotPrivate) {}
|
||||||
@ -6028,6 +6030,14 @@ void ConnectToPrivateSlot::test(SenderObject* obj1) {
|
|||||||
QVERIFY(!QObjectPrivate::disconnect(obj1, &SenderObject::signal2, d, &ConnectToPrivateSlotPrivate::thisIsAPrivateSlot));
|
QVERIFY(!QObjectPrivate::disconnect(obj1, &SenderObject::signal2, d, &ConnectToPrivateSlotPrivate::thisIsAPrivateSlot));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Compile test to verify that we can use QObjectPrivate::connect in
|
||||||
|
// the code of the private class, even if Q_DECLARE_PUBLIC is used in the
|
||||||
|
// private section of the private class.
|
||||||
|
void ConnectToPrivateSlotPrivate::testFromPrivate(SenderObject *obj)
|
||||||
|
{
|
||||||
|
QVERIFY(QObjectPrivate::connect(obj, &SenderObject::signal1, this, &ConnectToPrivateSlotPrivate::thisIsAPrivateSlot));
|
||||||
|
}
|
||||||
|
|
||||||
void tst_QObject::connectPrivateSlots()
|
void tst_QObject::connectPrivateSlots()
|
||||||
{
|
{
|
||||||
SenderObject sender;
|
SenderObject sender;
|
||||||
|
Loading…
Reference in New Issue
Block a user