summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/corelib/compat/removed_api.cpp7
-rw-r--r--src/corelib/kernel/qmetaobject.cpp48
-rw-r--r--src/corelib/kernel/qobjectdefs.h118
-rw-r--r--src/corelib/kernel/qobjectdefs_impl.h57
-rw-r--r--src/corelib/kernel/qtimer.cpp4
5 files changed, 206 insertions, 28 deletions
diff --git a/src/corelib/compat/removed_api.cpp b/src/corelib/compat/removed_api.cpp
index 088b418aef..a504bef17d 100644
--- a/src/corelib/compat/removed_api.cpp
+++ b/src/corelib/compat/removed_api.cpp
@@ -635,6 +635,13 @@ QString QLocale::bcp47Name() const
return bcp47Name(TagSeparator::Dash);
}
+#include "qobjectdefs.h"
+
+bool QMetaObject::invokeMethodImpl(QObject *object, QtPrivate::QSlotObjectBase *slot, Qt::ConnectionType type, void *ret)
+{
+ return invokeMethodImpl(object, slot, type, 1, &ret, nullptr, nullptr);
+}
+
#include "qurl.h"
QUrl QUrl::fromEncoded(const QByteArray &input, ParsingMode mode)
diff --git a/src/corelib/kernel/qmetaobject.cpp b/src/corelib/kernel/qmetaobject.cpp
index c6ab79718b..7445974404 100644
--- a/src/corelib/kernel/qmetaobject.cpp
+++ b/src/corelib/kernel/qmetaobject.cpp
@@ -1612,12 +1612,16 @@ bool QMetaObject::invokeMethodImpl(QObject *obj, const char *member, Qt::Connect
return printMethodNotFoundWarning(obj->metaObject(), name, paramCount, typeNames, metaTypes);
}
-bool QMetaObject::invokeMethodImpl(QObject *object, QtPrivate::QSlotObjectBase *slotObj,
- Qt::ConnectionType type, void *ret)
+bool QMetaObject::invokeMethodImpl(QObject *object, QtPrivate::QSlotObjectBase *slotObj, Qt::ConnectionType type,
+ qsizetype parameterCount, const void *const *params, const char *const *names,
+ const QtPrivate::QMetaTypeInterface * const *metaTypes)
{
+ // We don't need this now but maybe we want it later, or we may be able to
+ // share more code between the two invokeMethodImpl() overloads:
+ Q_UNUSED(names);
auto slot = QtPrivate::SlotObjUniquePtr(slotObj);
- if (! object)
+ if (! object) // ### only if the slot requires the object + not queued?
return false;
Qt::HANDLE currentThreadId = QThread::currentThreadId();
@@ -1629,8 +1633,7 @@ bool QMetaObject::invokeMethodImpl(QObject *object, QtPrivate::QSlotObjectBase *
if (type == Qt::AutoConnection)
type = receiverInSameThread ? Qt::DirectConnection : Qt::QueuedConnection;
- void *argv[] = { ret };
-
+ void **argv = const_cast<void **>(params);
if (type == Qt::DirectConnection) {
slot->call(object, argv);
} else if (type == Qt::QueuedConnection) {
@@ -1639,8 +1642,16 @@ bool QMetaObject::invokeMethodImpl(QObject *object, QtPrivate::QSlotObjectBase *
"queued connections");
return false;
}
+ auto event = std::make_unique<QMetaCallEvent>(std::move(slot), nullptr, -1, parameterCount);
+ void **args = event->args();
+ QMetaType *types = event->types();
- QCoreApplication::postEvent(object, new QMetaCallEvent(std::move(slot), nullptr, -1, 1));
+ for (int i = 1; i < parameterCount; ++i) {
+ types[i] = QMetaType(metaTypes[i]);
+ args[i] = types[i].create(argv[i]);
+ }
+
+ QCoreApplication::postEvent(object, event.release());
} else if (type == Qt::BlockingQueuedConnection) {
#if QT_CONFIG(thread)
if (receiverInSameThread)
@@ -1734,6 +1745,31 @@ bool QMetaObject::invokeMethodImpl(QObject *object, QtPrivate::QSlotObjectBase *
*/
/*!
+ \fn template<typename Functor, typename FunctorReturnType, typename... Args> bool QMetaObject::invokeMethod(QObject *context, Functor &&function, Qt::ConnectionType type, QTemplatedMetaMethodReturnArgument<FunctorReturnType> ret, Args &&...arguments)
+ \fn template<typename Functor, typename FunctorReturnType, typename... Args> bool QMetaObject::invokeMethod(QObject *context, Functor &&function, QTemplatedMetaMethodReturnArgument<FunctorReturnType> ret, Args &&...arguments)
+ \fn template<typename Functor, typename... Args> bool QMetaObject::invokeMethod(QObject *context, Functor &&function, Qt::ConnectionType type, Args &&...arguments)
+ \fn template<typename Functor, typename... Args> bool QMetaObject::invokeMethod(QObject *context, Functor &&function, Args &&...arguments)
+
+ \since 6.7
+ \threadsafe
+
+ Invokes the \a function with \a arguments in the event loop of \a context.
+ \a function can be a functor or a pointer to a member function. Returns
+ \c true if the function could be invoked. The return value of the
+ function call is placed in \a ret. The object used for the \a ret argument
+ should be obtained by passing your object to qReturnArg(). For example:
+
+ \badcode
+ MyClass *obj = ...;
+ int result = 0;
+ QMetaObject::invokeMethod(obj, &MyClass::myMethod, qReturnArg(result), parameter);
+ \endcode
+
+ If \a type is set, then the function is invoked using that connection type.
+ Otherwise, Qt::AutoConnection will be used.
+*/
+
+/*!
\fn QMetaObject::Connection &QMetaObject::Connection::operator=(Connection &&other)
Move-assigns \a other to this object, and returns a reference.
diff --git a/src/corelib/kernel/qobjectdefs.h b/src/corelib/kernel/qobjectdefs.h
index e024695a0b..71e7f00697 100644
--- a/src/corelib/kernel/qobjectdefs.h
+++ b/src/corelib/kernel/qobjectdefs.h
@@ -416,33 +416,101 @@ struct Q_CORE_EXPORT QMetaObject
static bool invokeMethod(QObject *context, Functor &&function, Qt::ConnectionType type = Qt::AutoConnection, FunctorReturnType *ret = nullptr);
template<typename Functor, typename FunctorReturnType>
static bool invokeMethod(QObject *context, Functor &&function, FunctorReturnType *ret);
+
+ template<typename Functor, typename FunctorReturnType, typename... Args>
+ static bool invokeMethod(QObject *context, Functor &&function, Qt::ConnectionType type, QTemplatedMetaMethodReturnArgument<FunctorReturnType> ret, Args &&...arguments);
+ template<typename Functor, typename FunctorReturnType, typename... Args>
+ static bool invokeMethod(QObject *context, Functor &&function, QTemplatedMetaMethodReturnArgument<FunctorReturnType> ret, Args &&...arguments);
+ template<typename Functor, typename... Args>
+ static bool invokeMethod(QObject *context, Functor &&function, Qt::ConnectionType type, Args &&...arguments);
+ template<typename Functor, typename... Args>
+ static bool invokeMethod(QObject *context, Functor &&function, Args &&...arguments);
#else
template <typename Func>
static std::enable_if_t<!std::disjunction_v<std::is_convertible<Func, const char *>,
QtPrivate::Invoke::AreOldStyleArgs<Func>>,
bool>
invokeMethod(typename QtPrivate::ContextTypeForFunctor<Func>::ContextType *object,
- Func &&function,
- Qt::ConnectionType type = Qt::AutoConnection,
- typename QtPrivate::Callable<Func>::ReturnType *ret = nullptr)
+ Func &&function, Qt::ConnectionType type,
+ typename QtPrivate::Callable<Func>::ReturnType *ret)
{
- static_assert(QtPrivate::Callable<Func>::ArgumentCount <= 0,
- "QMetaObject::invokeMethod cannot call functions with arguments!");
- using Prototype = typename QtPrivate::Callable<Func>::Function;
- return invokeMethodImpl(object, QtPrivate::makeCallableObject<Prototype>(std::forward<Func>(function)), type, ret);
+ using R = typename QtPrivate::Callable<Func>::ReturnType;
+ const auto getReturnArg = [ret]() -> QTemplatedMetaMethodReturnArgument<R> {
+ if constexpr (std::is_void_v<R>)
+ return {};
+ else
+ return ret ? qReturnArg(*ret) : QTemplatedMetaMethodReturnArgument<R>{};
+ };
+ return invokeMethod(object, std::forward<Func>(function), type, getReturnArg());
}
-
template <typename Func>
static std::enable_if_t<!std::disjunction_v<std::is_convertible<Func, const char *>,
QtPrivate::Invoke::AreOldStyleArgs<Func>>,
bool>
invokeMethod(typename QtPrivate::ContextTypeForFunctor<Func>::ContextType *object,
- Func &&function,
- typename QtPrivate::Callable<Func>::ReturnType *ret)
+ Func &&function, typename QtPrivate::Callable<Func>::ReturnType *ret)
{
return invokeMethod(object, std::forward<Func>(function), Qt::AutoConnection, ret);
}
+ template <typename Func, typename... Args>
+ static std::enable_if_t<!std::disjunction_v<std::is_convertible<Func, const char *>,
+ QtPrivate::Invoke::AreOldStyleArgs<Args...>>,
+ bool>
+ invokeMethod(typename QtPrivate::ContextTypeForFunctor<Func>::ContextType *object,
+ Func &&function, Qt::ConnectionType type,
+ QTemplatedMetaMethodReturnArgument<
+ typename QtPrivate::Callable<Func, Args...>::ReturnType>
+ ret,
+ Args &&...args)
+ {
+ return invokeMethodCallableHelper(object, std::forward<Func>(function), type, ret,
+ std::forward<Args>(args)...);
+ }
+
+ template <typename Func, typename... Args>
+ static std::enable_if_t<!std::disjunction_v<std::is_convertible<Func, const char *>,
+ QtPrivate::Invoke::AreOldStyleArgs<Args...>>,
+ bool>
+ invokeMethod(typename QtPrivate::ContextTypeForFunctor<Func>::ContextType *object,
+ Func &&function, Qt::ConnectionType type, Args &&...args)
+ {
+ using R = typename QtPrivate::Callable<Func, Args...>::ReturnType;
+ QTemplatedMetaMethodReturnArgument<R> r{ QtPrivate::qMetaTypeInterfaceForType<R>(), nullptr,
+ nullptr };
+ return invokeMethod(object, std::forward<Func>(function), type, r,
+ std::forward<Args>(args)...);
+ }
+
+ template <typename Func, typename... Args>
+ static std::enable_if_t<!std::disjunction_v<std::is_convertible<Func, const char *>,
+ QtPrivate::Invoke::AreOldStyleArgs<Args...>>,
+ bool>
+ invokeMethod(typename QtPrivate::ContextTypeForFunctor<Func>::ContextType *object,
+ Func &&function,
+ QTemplatedMetaMethodReturnArgument<
+ typename QtPrivate::Callable<Func, Args...>::ReturnType>
+ ret,
+ Args &&...args)
+ {
+ return invokeMethod(object, std::forward<Func>(function), Qt::AutoConnection, ret,
+ std::forward<Args>(args)...);
+ }
+
+ template <typename Func, typename... Args>
+ static std::enable_if_t<!std::disjunction_v<std::is_convertible<Func, const char *>,
+ QtPrivate::Invoke::AreOldStyleArgs<Args...>>,
+ bool>
+ invokeMethod(typename QtPrivate::ContextTypeForFunctor<Func>::ContextType *object,
+ Func &&function, Args &&...args)
+ {
+ using R = typename QtPrivate::Callable<Func, Args...>::ReturnType;
+ QTemplatedMetaMethodReturnArgument<R> r{ QtPrivate::qMetaTypeInterfaceForType<R>(), nullptr,
+ nullptr };
+ return invokeMethod(object, std::forward<Func>(function), Qt::AutoConnection, r,
+ std::forward<Args>(args)...);
+ }
+
#endif
#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
@@ -530,10 +598,40 @@ struct Q_CORE_EXPORT QMetaObject
} d;
private:
+ // Just need to have this here with a separate name so the other inline
+ // functions can call this without any ambiguity
+ template <typename Func, typename... Args>
+ static bool
+ invokeMethodCallableHelper(typename QtPrivate::ContextTypeForFunctor<Func>::ContextType *object,
+ Func &&function, Qt::ConnectionType type, const QMetaMethodReturnArgument &ret,
+ Args &&...args)
+ {
+ using Callable = QtPrivate::Callable<Func, Args...>;
+ using ExpectedArguments = typename Callable::Arguments;
+ static_assert(sizeof...(Args) <= ExpectedArguments::size, "Too many arguments");
+ using ActualArguments = QtPrivate::List<Args...>;
+ static_assert(QtPrivate::CheckCompatibleArguments<ActualArguments,
+ ExpectedArguments>::value,
+ "Incompatible arguments");
+
+ auto h = QtPrivate::invokeMethodHelper(ret, args...);
+
+ auto callable = new QtPrivate::QCallableObject<std::decay_t<Func>, ActualArguments,
+ typename Callable::ReturnType>(std::forward<Func>(function));
+ return invokeMethodImpl(object, callable, type, h.parameterCount(), h.parameters.data(),
+ h.typeNames.data(), h.metaTypes.data());
+ }
+
static bool invokeMethodImpl(QObject *object, const char *member, Qt::ConnectionType type,
qsizetype parameterCount, const void *const *parameters, const char *const *names,
const QtPrivate::QMetaTypeInterface * const *metaTypes);
+ static bool invokeMethodImpl(QObject *object, QtPrivate::QSlotObjectBase *slotObj,
+ Qt::ConnectionType type, qsizetype parameterCount,
+ const void *const *params, const char *const *names,
+ const QtPrivate::QMetaTypeInterface *const *metaTypes);
+#if QT_CORE_REMOVED_SINCE(6, 7)
static bool invokeMethodImpl(QObject *object, QtPrivate::QSlotObjectBase *slot, Qt::ConnectionType type, void *ret);
+#endif
static QObject *newInstanceImpl(const QMetaObject *mobj, qsizetype parameterCount,
const void **parameters, const char **typeNames,
const QtPrivate::QMetaTypeInterface **metaTypes);
diff --git a/src/corelib/kernel/qobjectdefs_impl.h b/src/corelib/kernel/qobjectdefs_impl.h
index a45792c5d7..72928f2235 100644
--- a/src/corelib/kernel/qobjectdefs_impl.h
+++ b/src/corelib/kernel/qobjectdefs_impl.h
@@ -340,20 +340,55 @@ namespace QtPrivate {
}
};
- template<typename Func>
- struct ZeroArgFunctor : Functor<Func, 0>
+ template<typename Func, typename... Args>
+ struct FunctorCallable : Functor<Func, sizeof...(Args)>
{
- using ReturnType = decltype(std::declval<Func>()());
- using Function = ReturnType(*)();
- enum {ArgumentCount = 0};
- using Arguments = QtPrivate::List<>;
+ using ReturnType = decltype(std::declval<Func>()(std::declval<Args>()...));
+ using Function = ReturnType(*)(Args...);
+ enum {ArgumentCount = sizeof...(Args)};
+ using Arguments = QtPrivate::List<Args...>;
};
- template<typename Func>
- using Callable = std::conditional_t<FunctionPointer<std::decay_t<Func>>::ArgumentCount == -1,
- ZeroArgFunctor<std::decay_t<Func>>,
- FunctionPointer<std::decay_t<Func>>
- >;
+ template <typename Functor, typename... Args>
+ struct HasCallOperatorAcceptingArgs
+ {
+ private:
+ template <typename F, typename = void>
+ struct Test : std::false_type
+ {
+ };
+ // We explicitly use .operator() to not return true for pointers to free/static function
+ template <typename F>
+ struct Test<F, std::void_t<decltype(std::declval<F>().operator()(std::declval<Args>()...))>>
+ : std::true_type
+ {
+ };
+
+ public:
+ using Type = Test<Functor>;
+ static constexpr bool value = Type::value;
+ };
+
+ template <typename Functor, typename... Args>
+ constexpr bool
+ HasCallOperatorAcceptingArgs_v = HasCallOperatorAcceptingArgs<Functor, Args...>::value;
+
+ template <typename Func, typename... Args>
+ struct CallableHelper
+ {
+ private:
+ // Could've been std::conditional_t, but that requires all branches to
+ // be valid
+ static auto Resolve(std::true_type CallOperator) -> FunctorCallable<Func, Args...>;
+ static auto Resolve(std::false_type CallOperator) -> FunctionPointer<std::decay_t<Func>>;
+
+ public:
+ using Type = decltype(Resolve(typename HasCallOperatorAcceptingArgs<std::decay_t<Func>,
+ Args...>::Type{}));
+ };
+
+ template<typename Func, typename... Args>
+ using Callable = typename CallableHelper<Func, Args...>::Type;
/*
Wrapper around ComputeFunctorArgumentCount and CheckCompatibleArgument,
diff --git a/src/corelib/kernel/qtimer.cpp b/src/corelib/kernel/qtimer.cpp
index 6487eb472e..4502e20a42 100644
--- a/src/corelib/kernel/qtimer.cpp
+++ b/src/corelib/kernel/qtimer.cpp
@@ -366,8 +366,10 @@ void QTimer::singleShotImpl(int msec, Qt::TimerType timerType,
deleteReceiver = true;
}
+ auto h = QtPrivate::invokeMethodHelper({});
QMetaObject::invokeMethodImpl(const_cast<QObject *>(receiver), slotObj,
- Qt::QueuedConnection, nullptr);
+ Qt::QueuedConnection, h.parameterCount(), h.parameters.data(), h.typeNames.data(),
+ h.metaTypes.data());
if (deleteReceiver)
const_cast<QObject *>(receiver)->deleteLater();