diff options
author | Volker Hilsheimer <[email protected]> | 2023-04-27 16:26:32 +0200 |
---|---|---|
committer | Volker Hilsheimer <[email protected]> | 2023-04-28 07:45:22 +0200 |
commit | 9958edba41ac49097a54e0872c3c4934d2dd81f9 (patch) | |
tree | d6250c1adab075142033febd690c849830bfced9 | |
parent | bd69821074d62a6e8b5eca56d7b9307e1b3e8645 (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.h | 24 | ||||
-rw-r--r-- | src/corelib/kernel/qobjectdefs_impl.h | 8 | ||||
-rw-r--r-- | tests/auto/corelib/kernel/qobject/tst_qobject.cpp | 11 |
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)); |