summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVolker Hilsheimer <[email protected]>2023-04-27 16:26:32 +0200
committerVolker Hilsheimer <[email protected]>2023-04-28 07:45:22 +0200
commit9958edba41ac49097a54e0872c3c4934d2dd81f9 (patch)
treed6250c1adab075142033febd690c849830bfced9
parentbd69821074d62a6e8b5eca56d7b9307e1b3e8645 (diff)
Support move-only functors in invokeMethod and async APIs
Move-only functors must never be passed by value, so fix the QFunctorSlotObject constructor accordingly. This then requires adjustments to the various QMetaMethod::invokeMethod overloads, as those must also perfectly forwad the functor type. Enable the previously failing test case for move-only functors. Change-Id: I9c544fd3ddbc5e1da3ca193236291a9f83d86211 Reviewed-by: Thiago Macieira <[email protected]>
-rw-r--r--src/corelib/kernel/qobjectdefs.h24
-rw-r--r--src/corelib/kernel/qobjectdefs_impl.h8
-rw-r--r--tests/auto/corelib/kernel/qobject/tst_qobject.cpp11
3 files changed, 20 insertions, 23 deletions
diff --git a/src/corelib/kernel/qobjectdefs.h b/src/corelib/kernel/qobjectdefs.h
index 28b4e368fe8..982af5a18a0 100644
--- a/src/corelib/kernel/qobjectdefs.h
+++ b/src/corelib/kernel/qobjectdefs.h
@@ -417,11 +417,11 @@ struct Q_CORE_EXPORT QMetaObject
&& !std::is_convertible<Func, const char*>::value
&& QtPrivate::FunctionPointer<Func>::ArgumentCount == 0, bool>::type
invokeMethod(typename QtPrivate::FunctionPointer<Func>::Object *object,
- Func function,
+ Func &&function,
Qt::ConnectionType type = Qt::AutoConnection,
typename QtPrivate::FunctionPointer<Func>::ReturnType *ret = nullptr)
{
- return invokeMethodImpl(object, new QtPrivate::QSlotObjectWithNoArgs<Func>(function), type, ret);
+ return invokeMethodImpl(object, new QtPrivate::QSlotObjectWithNoArgs<Func>(std::forward<Func>(function)), type, ret);
}
template <typename Func>
@@ -429,10 +429,10 @@ struct Q_CORE_EXPORT QMetaObject
&& !std::is_convertible<Func, const char*>::value
&& QtPrivate::FunctionPointer<Func>::ArgumentCount == 0, bool>::type
invokeMethod(typename QtPrivate::FunctionPointer<Func>::Object *object,
- Func function,
+ Func &&function,
typename QtPrivate::FunctionPointer<Func>::ReturnType *ret)
{
- return invokeMethodImpl(object, new QtPrivate::QSlotObjectWithNoArgs<Func>(function), Qt::AutoConnection, ret);
+ return invokeMethodImpl(object, new QtPrivate::QSlotObjectWithNoArgs<Func>(std::forward<Func>(function)), Qt::AutoConnection, ret);
}
// invokeMethod() for function pointer (not member)
@@ -440,21 +440,21 @@ struct Q_CORE_EXPORT QMetaObject
static typename std::enable_if<!QtPrivate::FunctionPointer<Func>::IsPointerToMemberFunction
&& !std::is_convertible<Func, const char*>::value
&& QtPrivate::FunctionPointer<Func>::ArgumentCount == 0, bool>::type
- invokeMethod(QObject *context, Func function,
+ invokeMethod(QObject *context, Func &&function,
Qt::ConnectionType type = Qt::AutoConnection,
typename QtPrivate::FunctionPointer<Func>::ReturnType *ret = nullptr)
{
- return invokeMethodImpl(context, new QtPrivate::QFunctorSlotObjectWithNoArgsImplicitReturn<Func>(function), type, ret);
+ return invokeMethodImpl(context, new QtPrivate::QFunctorSlotObjectWithNoArgsImplicitReturn<Func>(std::forward<Func>(function)), type, ret);
}
template <typename Func>
static typename std::enable_if<!QtPrivate::FunctionPointer<Func>::IsPointerToMemberFunction
&& !std::is_convertible<Func, const char*>::value
&& QtPrivate::FunctionPointer<Func>::ArgumentCount == 0, bool>::type
- invokeMethod(QObject *context, Func function,
+ invokeMethod(QObject *context, Func &&function,
typename QtPrivate::FunctionPointer<Func>::ReturnType *ret)
{
- return invokeMethodImpl(context, new QtPrivate::QFunctorSlotObjectWithNoArgsImplicitReturn<Func>(function), Qt::AutoConnection, ret);
+ return invokeMethodImpl(context, new QtPrivate::QFunctorSlotObjectWithNoArgsImplicitReturn<Func>(std::forward<Func>(function)), Qt::AutoConnection, ret);
}
// invokeMethod() for Functor
@@ -462,11 +462,11 @@ struct Q_CORE_EXPORT QMetaObject
static typename std::enable_if<!QtPrivate::FunctionPointer<Func>::IsPointerToMemberFunction
&& QtPrivate::FunctionPointer<Func>::ArgumentCount == -1
&& !std::is_convertible<Func, const char*>::value, bool>::type
- invokeMethod(QObject *context, Func function,
+ invokeMethod(QObject *context, Func &&function,
Qt::ConnectionType type = Qt::AutoConnection, decltype(function()) *ret = nullptr)
{
return invokeMethodImpl(context,
- new QtPrivate::QFunctorSlotObjectWithNoArgs<Func, decltype(function())>(std::move(function)),
+ new QtPrivate::QFunctorSlotObjectWithNoArgs<Func, decltype(function())>(std::forward<Func>(function)),
type,
ret);
}
@@ -475,10 +475,10 @@ struct Q_CORE_EXPORT QMetaObject
static typename std::enable_if<!QtPrivate::FunctionPointer<Func>::IsPointerToMemberFunction
&& QtPrivate::FunctionPointer<Func>::ArgumentCount == -1
&& !std::is_convertible<Func, const char*>::value, bool>::type
- invokeMethod(QObject *context, Func function, decltype(function()) *ret)
+ invokeMethod(QObject *context, Func &&function, decltype(function()) *ret)
{
return invokeMethodImpl(context,
- new QtPrivate::QFunctorSlotObjectWithNoArgs<Func, decltype(function())>(std::move(function)),
+ new QtPrivate::QFunctorSlotObjectWithNoArgs<Func, decltype(function())>(std::forward<Func>(function)),
Qt::AutoConnection,
ret);
}
diff --git a/src/corelib/kernel/qobjectdefs_impl.h b/src/corelib/kernel/qobjectdefs_impl.h
index 3c3457f6941..e8b9b4a2091 100644
--- a/src/corelib/kernel/qobjectdefs_impl.h
+++ b/src/corelib/kernel/qobjectdefs_impl.h
@@ -439,7 +439,7 @@ namespace QtPrivate {
}
}
public:
- explicit QFunctorSlotObject(Func f) : QSlotObjectBase(&impl), function(std::move(f)) {}
+ explicit QFunctorSlotObject(Func &&f) : QSlotObjectBase(&impl), function(std::forward<Func>(f)) {}
};
// typedefs for readability for when there are no parameters
@@ -492,7 +492,7 @@ namespace QtPrivate {
template <typename Prototype, typename Functor>
static constexpr std::enable_if_t<QtPrivate::countMatchingArguments<Prototype, Functor>() >= 0,
QtPrivate::QSlotObjectBase *>
- makeSlotObject(Functor func)
+ makeSlotObject(Functor &&func)
{
using ExpectedSignature = QtPrivate::FunctionPointer<Prototype>;
using ExpectedArguments = typename ExpectedSignature::Arguments;
@@ -503,13 +503,13 @@ namespace QtPrivate {
if constexpr (QtPrivate::FunctionPointer<Functor>::IsPointerToMemberFunction) {
using ActualArguments = typename ActualSignature::Arguments;
- return new QtPrivate::QSlotObject<Functor, ActualArguments, void>(func);
+ return new QtPrivate::QSlotObject<Functor, ActualArguments, void>(std::forward<Functor>(func));
} else {
constexpr int MatchingArgumentCount = QtPrivate::countMatchingArguments<Prototype, Functor>();
using ActualArguments = typename QtPrivate::List_Left<ExpectedArguments, MatchingArgumentCount>::Value;
return new QtPrivate::QFunctorSlotObject<Functor, MatchingArgumentCount,
- ActualArguments, void>(std::move(func));
+ ActualArguments, void>(std::forward<Functor>(func));
}
}
}
diff --git a/tests/auto/corelib/kernel/qobject/tst_qobject.cpp b/tests/auto/corelib/kernel/qobject/tst_qobject.cpp
index 9c18a2a0f60..649f075a02e 100644
--- a/tests/auto/corelib/kernel/qobject/tst_qobject.cpp
+++ b/tests/auto/corelib/kernel/qobject/tst_qobject.cpp
@@ -8434,6 +8434,7 @@ void tst_QObject::asyncCallbackHelper()
static_assert(compiles<AsyncCaller::Prototype0>(&AsyncCaller::callback0));
static_assert(compiles<AsyncCaller::Prototype0>(&AsyncCaller::staticCallback0));
static_assert(compiles<AsyncCaller::Prototype0>(lambda0));
+ static_assert(compiles<AsyncCaller::Prototype0>(moveOnlyLambda));
static_assert(compiles<AsyncCaller::Prototype0>(freeFunction0));
static_assert(compiles<AsyncCaller::Prototype0>(functor0));
@@ -8448,6 +8449,7 @@ void tst_QObject::asyncCallbackHelper()
static_assert(compiles<AsyncCaller::Prototype1>(&AsyncCaller::callback1));
static_assert(compiles<AsyncCaller::Prototype1>(&AsyncCaller::staticCallback1));
static_assert(compiles<AsyncCaller::Prototype1>(lambda1));
+ static_assert(compiles<AsyncCaller::Prototype1>(moveOnlyLambda));
static_assert(compiles<AsyncCaller::Prototype1>(constLambda));
static_assert(compiles<AsyncCaller::Prototype1>(freeFunction1));
static_assert(compiles<AsyncCaller::Prototype1>(functor1));
@@ -8461,11 +8463,6 @@ void tst_QObject::asyncCallbackHelper()
static_assert(!compiles<AsyncCaller::Prototype0>(freeFunction1));
static_assert(!compiles<AsyncCaller::Prototype0>(functor1));
- // move-only functor - should work, but doesn't because QFunctorSlotObject requires
- // the functor to be of a copyable type!
- static_assert(!compiles<AsyncCaller::Prototype0>(moveOnlyLambda));
- static_assert(!compiles<AsyncCaller::Prototype1>(moveOnlyLambda));
-
// wrong parameter type
static_assert(!compiles<AsyncCaller::Prototype1>(&AsyncCaller::callbackInt));
@@ -8483,7 +8480,7 @@ void tst_QObject::asyncCallbackHelper()
QVERIFY(caller.callMe0(&caller, &AsyncCaller::staticCallback0));
QVERIFY(caller.callMe0(&caller, lambda0));
QVERIFY(caller.callMe0(&caller, freeFunction0));
-// QVERIFY(caller.callMe0(&caller, moveOnlyLambda));
+ QVERIFY(caller.callMe0(&caller, moveOnlyLambda));
QVERIFY(caller.callMe1(&caller, &AsyncCaller::callback1));
QVERIFY(caller.callMe1(&caller, &AsyncCaller::staticCallback1));
@@ -8495,7 +8492,7 @@ void tst_QObject::asyncCallbackHelper()
QVERIFY(caller.callMe0(&AsyncCaller::staticCallback0));
QVERIFY(caller.callMe0(lambda0));
QVERIFY(caller.callMe0(freeFunction0));
-// QVERIFY(caller.callMe0(moveOnlyLambda));
+ QVERIFY(caller.callMe0(moveOnlyLambda));
QVERIFY(caller.callMe1(&AsyncCaller::staticCallback1));
QVERIFY(caller.callMe1(lambda1));