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 <thiago.macieira@intel.com>
This commit is contained in:
parent
bd69821074
commit
9958edba41
@ -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);
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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));
|
||||
|
Loading…
Reference in New Issue
Block a user