Merge QSlotObject and QFunctorSlotObject, and use helpers to deduplicate
Now we can use QFunctorSlotObject for any kind of callable - free function, functor, or PMF. This allows us to fold the various overloads of QObject::connect together, removing duplicate code and error handling logic. Change-Id: I8842f5ddd29e86be07a422647a8fc1678fd534b1 Reviewed-by: Thiago Macieira <thiago.macieira@intel.com> Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
This commit is contained in:
parent
76e25bdfdf
commit
642f799fc6
@ -192,121 +192,55 @@ public:
|
||||
template<typename PointerToMemberFunction, typename Functor>
|
||||
static QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, const QObject *context, Functor functor, Qt::ConnectionType type = Qt::AutoConnection);
|
||||
#else
|
||||
//Connect a signal to a pointer to qobject member function
|
||||
//connect with context
|
||||
template <typename Func1, typename Func2>
|
||||
static inline QMetaObject::Connection connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal,
|
||||
const typename QtPrivate::FunctionPointer<Func2>::Object *receiver, Func2 slot,
|
||||
Qt::ConnectionType type = Qt::AutoConnection)
|
||||
{
|
||||
typedef QtPrivate::FunctionPointer<Func1> SignalType;
|
||||
typedef QtPrivate::FunctionPointer<Func2> SlotType;
|
||||
|
||||
static_assert(QtPrivate::HasQ_OBJECT_Macro<typename SignalType::Object>::Value,
|
||||
"No Q_OBJECT in the class with the signal");
|
||||
|
||||
//compilation error if the arguments does not match.
|
||||
static_assert(int(SignalType::ArgumentCount) >= int(SlotType::ArgumentCount),
|
||||
"The slot requires more arguments than the signal provides.");
|
||||
static_assert((QtPrivate::CheckCompatibleArguments<typename SignalType::Arguments, typename SlotType::Arguments>::value),
|
||||
"Signal and slot arguments are not compatible.");
|
||||
static_assert((QtPrivate::AreArgumentsCompatible<typename SlotType::ReturnType, typename SignalType::ReturnType>::value),
|
||||
"Return type of the slot is not compatible with the return type of the signal.");
|
||||
|
||||
const int *types = nullptr;
|
||||
if (type == Qt::QueuedConnection || type == Qt::BlockingQueuedConnection)
|
||||
types = QtPrivate::ConnectionTypes<typename SignalType::Arguments>::types();
|
||||
|
||||
return connectImpl(sender, reinterpret_cast<void **>(&signal),
|
||||
receiver, reinterpret_cast<void **>(&slot),
|
||||
new QtPrivate::QSlotObject<Func2, typename QtPrivate::List_Left<typename SignalType::Arguments, SlotType::ArgumentCount>::Value,
|
||||
typename SignalType::ReturnType>(slot),
|
||||
type, types, &SignalType::Object::staticMetaObject);
|
||||
}
|
||||
|
||||
//connect to a function pointer (not a member)
|
||||
template <typename Func1, typename Func2>
|
||||
static inline typename std::enable_if<int(QtPrivate::FunctionPointer<Func2>::ArgumentCount) >= 0, QMetaObject::Connection>::type
|
||||
connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal, Func2 &&slot)
|
||||
{
|
||||
return connect(sender, signal, sender, std::forward<Func2>(slot), Qt::DirectConnection);
|
||||
}
|
||||
|
||||
//connect to a function pointer (not a member)
|
||||
template <typename Func1, typename Func2>
|
||||
static inline typename std::enable_if<int(QtPrivate::FunctionPointer<std::decay_t<Func2>>::ArgumentCount) >= 0 &&
|
||||
!QtPrivate::FunctionPointer<std::decay_t<Func2>>::IsPointerToMemberFunction, QMetaObject::Connection>::type
|
||||
connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal, const QObject *context, Func2 &&slot,
|
||||
Qt::ConnectionType type = Qt::AutoConnection)
|
||||
static inline QMetaObject::Connection
|
||||
connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal,
|
||||
const typename QtPrivate::ContextTypeForFunctor<Func2>::ContextType *context, Func2 &&slot,
|
||||
Qt::ConnectionType type = Qt::AutoConnection)
|
||||
{
|
||||
typedef QtPrivate::FunctionPointer<Func1> SignalType;
|
||||
typedef QtPrivate::FunctionPointer<std::decay_t<Func2>> SlotType;
|
||||
|
||||
if constexpr (SlotType::ArgumentCount != -1) {
|
||||
static_assert((QtPrivate::AreArgumentsCompatible<typename SlotType::ReturnType, typename SignalType::ReturnType>::value),
|
||||
"Return type of the slot is not compatible with the return type of the signal.");
|
||||
} else {
|
||||
constexpr int FunctorArgumentCount = QtPrivate::ComputeFunctorArgumentCount<std::decay_t<Func2>, typename SignalType::Arguments>::Value;
|
||||
constexpr int SlotArgumentCount = (FunctorArgumentCount >= 0) ? FunctorArgumentCount : 0;
|
||||
typedef typename QtPrivate::FunctorReturnType<std::decay_t<Func2>, typename QtPrivate::List_Left<typename SignalType::Arguments, SlotArgumentCount>::Value>::Value SlotReturnType;
|
||||
|
||||
static_assert((QtPrivate::AreArgumentsCompatible<SlotReturnType, typename SignalType::ReturnType>::value),
|
||||
"Return type of the slot is not compatible with the return type of the signal.");
|
||||
}
|
||||
|
||||
static_assert(QtPrivate::HasQ_OBJECT_Macro<typename SignalType::Object>::Value,
|
||||
"No Q_OBJECT in the class with the signal");
|
||||
|
||||
//compilation error if the arguments does not match.
|
||||
static_assert(int(SignalType::ArgumentCount) >= int(SlotType::ArgumentCount),
|
||||
"The slot requires more arguments than the signal provides.");
|
||||
static_assert((QtPrivate::CheckCompatibleArguments<typename SignalType::Arguments, typename SlotType::Arguments>::value),
|
||||
"Signal and slot arguments are not compatible.");
|
||||
static_assert((QtPrivate::AreArgumentsCompatible<typename SlotType::ReturnType, typename SignalType::ReturnType>::value),
|
||||
"Return type of the slot is not compatible with the return type of the signal.");
|
||||
|
||||
const int *types = nullptr;
|
||||
if (type == Qt::QueuedConnection || type == Qt::BlockingQueuedConnection)
|
||||
types = QtPrivate::ConnectionTypes<typename SignalType::Arguments>::types();
|
||||
|
||||
return connectImpl(sender, reinterpret_cast<void **>(&signal), context, nullptr,
|
||||
new QtPrivate::QFunctorSlotObject<Func2,
|
||||
typename QtPrivate::List_Left<typename SignalType::Arguments, SlotType::ArgumentCount>::Value,
|
||||
typename SignalType::ReturnType>(std::forward<Func2>(slot)),
|
||||
void **pSlot = nullptr;
|
||||
if constexpr (std::is_member_function_pointer_v<std::decay_t<Func2>>)
|
||||
pSlot = const_cast<void **>(reinterpret_cast<void *const *>(&slot));
|
||||
|
||||
return connectImpl(sender, reinterpret_cast<void **>(&signal), context, pSlot,
|
||||
QtPrivate::makeSlotObject<Func1>(std::forward<Func2>(slot)),
|
||||
type, types, &SignalType::Object::staticMetaObject);
|
||||
}
|
||||
|
||||
//connect to a functor
|
||||
//connect without context
|
||||
template <typename Func1, typename Func2>
|
||||
static inline typename std::enable_if<
|
||||
QtPrivate::FunctionPointer<Func2>::ArgumentCount == -1 &&
|
||||
!std::is_convertible_v<Func2, const char*>, // don't match old-style connect
|
||||
QMetaObject::Connection>::type
|
||||
connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal, Func2 &&slot)
|
||||
static inline QMetaObject::Connection
|
||||
connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal, Func2 &&slot)
|
||||
{
|
||||
return connect(sender, signal, sender, std::forward<Func2>(slot), Qt::DirectConnection);
|
||||
}
|
||||
|
||||
//connect to a functor, with a "context" object defining in which event loop is going to be executed
|
||||
template <typename Func1, typename Func2>
|
||||
static inline typename std::enable_if<
|
||||
QtPrivate::FunctionPointer<Func2>::ArgumentCount == -1 &&
|
||||
!std::is_convertible_v<Func2, const char*>, // don't match old-style connect
|
||||
QMetaObject::Connection>::type
|
||||
connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal, const QObject *context, Func2 slot,
|
||||
Qt::ConnectionType type = Qt::AutoConnection)
|
||||
{
|
||||
typedef QtPrivate::FunctionPointer<Func1> SignalType;
|
||||
const int FunctorArgumentCount = QtPrivate::ComputeFunctorArgumentCount<Func2 , typename SignalType::Arguments>::Value;
|
||||
|
||||
static_assert((FunctorArgumentCount >= 0),
|
||||
"Signal and slot arguments are not compatible.");
|
||||
const int SlotArgumentCount = (FunctorArgumentCount >= 0) ? FunctorArgumentCount : 0;
|
||||
typedef typename QtPrivate::FunctorReturnType<Func2, typename QtPrivate::List_Left<typename SignalType::Arguments, SlotArgumentCount>::Value>::Value SlotReturnType;
|
||||
|
||||
static_assert((QtPrivate::AreArgumentsCompatible<SlotReturnType, typename SignalType::ReturnType>::value),
|
||||
"Return type of the slot is not compatible with the return type of the signal.");
|
||||
|
||||
static_assert(QtPrivate::HasQ_OBJECT_Macro<typename SignalType::Object>::Value,
|
||||
"No Q_OBJECT in the class with the signal");
|
||||
|
||||
const int *types = nullptr;
|
||||
if (type == Qt::QueuedConnection || type == Qt::BlockingQueuedConnection)
|
||||
types = QtPrivate::ConnectionTypes<typename SignalType::Arguments>::types();
|
||||
|
||||
return connectImpl(sender, reinterpret_cast<void **>(&signal), context, nullptr,
|
||||
new QtPrivate::QFunctorSlotObject<Func2,
|
||||
typename QtPrivate::List_Left<typename SignalType::Arguments, SlotArgumentCount>::Value,
|
||||
typename SignalType::ReturnType>(std::move(slot)),
|
||||
type, types, &SignalType::Object::staticMetaObject);
|
||||
}
|
||||
#endif //Q_QDOC
|
||||
|
||||
static bool disconnect(const QObject *sender, const char *signal,
|
||||
|
@ -401,35 +401,14 @@ namespace QtPrivate {
|
||||
Q_DISABLE_COPY_MOVE(QSlotObjectBase)
|
||||
};
|
||||
|
||||
// implementation of QSlotObjectBase for which the slot is a pointer to member function of a QObject
|
||||
// Args and R are the List of arguments and the return type of the signal to which the slot is connected.
|
||||
template<typename Func, typename Args, typename R> class QSlotObject : public QSlotObjectBase
|
||||
{
|
||||
typedef QtPrivate::FunctionPointer<Func> FuncType;
|
||||
Func function;
|
||||
static void impl(int which, QSlotObjectBase *this_, QObject *r, void **a, bool *ret)
|
||||
{
|
||||
switch (which) {
|
||||
case Destroy:
|
||||
delete static_cast<QSlotObject*>(this_);
|
||||
break;
|
||||
case Call:
|
||||
FuncType::template call<Args, R>(static_cast<QSlotObject*>(this_)->function, static_cast<typename FuncType::Object *>(r), a);
|
||||
break;
|
||||
case Compare:
|
||||
*ret = *reinterpret_cast<Func *>(a) == static_cast<QSlotObject*>(this_)->function;
|
||||
break;
|
||||
case NumOperations: ;
|
||||
}
|
||||
}
|
||||
public:
|
||||
explicit QSlotObject(Func f) : QSlotObjectBase(&impl), function(f) {}
|
||||
};
|
||||
// implementation of QSlotObjectBase for which the slot is a functor (or lambda)
|
||||
// Args and R are the List of arguments and the return type of the signal to which the slot is connected.
|
||||
template<typename Func, typename Args, typename R> class QFunctorSlotObject : public QSlotObjectBase
|
||||
{
|
||||
using FuncType = QtPrivate::Functor<Func, Args::size>;
|
||||
using FuncType = std::conditional_t<std::is_member_function_pointer_v<std::decay_t<Func>>,
|
||||
QtPrivate::FunctionPointer<std::decay_t<Func>>,
|
||||
QtPrivate::Functor<Func, Args::size>
|
||||
>;
|
||||
Func function;
|
||||
static void impl(int which, QSlotObjectBase *this_, QObject *r, void **a, bool *ret)
|
||||
{
|
||||
@ -438,9 +417,18 @@ namespace QtPrivate {
|
||||
delete static_cast<QFunctorSlotObject*>(this_);
|
||||
break;
|
||||
case Call:
|
||||
FuncType::template call<Args, R>(static_cast<QFunctorSlotObject*>(this_)->function, r, a);
|
||||
if constexpr (std::is_member_function_pointer_v<std::decay_t<Func>>)
|
||||
FuncType::template call<Args, R>(static_cast<QFunctorSlotObject*>(this_)->function, static_cast<typename FuncType::Object *>(r), a);
|
||||
else
|
||||
FuncType::template call<Args, R>(static_cast<QFunctorSlotObject*>(this_)->function, r, a);
|
||||
break;
|
||||
case Compare: // not implemented
|
||||
case Compare:
|
||||
if constexpr (std::is_member_function_pointer_v<std::decay_t<Func>>) {
|
||||
*ret = *reinterpret_cast<std::decay_t<Func> *>(a) == static_cast<QFunctorSlotObject*>(this_)->function;
|
||||
break;
|
||||
}
|
||||
// not implemented otherwise
|
||||
Q_FALLTHROUGH();
|
||||
case NumOperations:
|
||||
Q_UNUSED(ret);
|
||||
}
|
||||
@ -451,7 +439,7 @@ namespace QtPrivate {
|
||||
|
||||
// typedefs for readability for when there are no parameters
|
||||
template <typename Func>
|
||||
using QSlotObjectWithNoArgs = QSlotObject<Func,
|
||||
using QSlotObjectWithNoArgs = QFunctorSlotObject<Func,
|
||||
QtPrivate::List<>,
|
||||
typename QtPrivate::FunctionPointer<Func>::ReturnType>;
|
||||
|
||||
@ -506,19 +494,15 @@ namespace QtPrivate {
|
||||
using ExpectedSignature = QtPrivate::FunctionPointer<Prototype>;
|
||||
using ExpectedReturnType = typename ExpectedSignature::ReturnType;
|
||||
using ExpectedArguments = typename ExpectedSignature::Arguments;
|
||||
|
||||
using ActualSignature = QtPrivate::FunctionPointer<Functor>;
|
||||
constexpr int MatchingArgumentCount = QtPrivate::countMatchingArguments<Prototype, Functor>();
|
||||
using ActualArguments = typename QtPrivate::List_Left<ExpectedArguments, MatchingArgumentCount>::Value;
|
||||
|
||||
static_assert(int(ActualSignature::ArgumentCount) <= int(ExpectedSignature::ArgumentCount),
|
||||
"Functor requires more arguments than what can be provided.");
|
||||
|
||||
if constexpr (QtPrivate::FunctionPointer<Functor>::IsPointerToMemberFunction) {
|
||||
using ActualArguments = typename ActualSignature::Arguments;
|
||||
return new QtPrivate::QSlotObject<Functor, ActualArguments, ExpectedReturnType>(std::move(func));
|
||||
} else {
|
||||
constexpr int MatchingArgumentCount = QtPrivate::countMatchingArguments<Prototype, Functor>();
|
||||
using ActualArguments = typename QtPrivate::List_Left<ExpectedArguments, MatchingArgumentCount>::Value;
|
||||
return new QtPrivate::QFunctorSlotObject<Functor, ActualArguments, ExpectedReturnType>(std::move(func));
|
||||
}
|
||||
return new QtPrivate::QFunctorSlotObject<Functor, ActualArguments, ExpectedReturnType>(std::forward<Functor>(func));
|
||||
}
|
||||
|
||||
template<typename Prototype, typename Functor, typename = void>
|
||||
|
Loading…
x
Reference in New Issue
Block a user