Don't copy the functor object for each signal emission

The behavior was different in the variadic template code and in the C++98
code. The code without variadic template support was not copying the functor
object (e.g. a lambda) before calling it.
However, in the variadic template section, QtPrivate::FunctorCall::call
took the functor by value instead of by reference resulting in a copy.

QtPrivate::FunctorCall::call is a helper function for
QtPrivate::FunctionPointer::call which is only needed for variadic template
expension.

[ChangeLog][QtCore][QObject] If the compiler supports variadic templates,
no longer copy functor connected to a signal each time the signal is
emitted. Restoring the C++98 behavior.

Task-number: QTBUG-52542
Change-Id: I3ca20ef6910893b8a288e70af7de4c7b69502173
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
bb10
Olivier Goffart 2016-04-12 16:05:10 +02:00 committed by Shawn Rutledge
parent 3b98467ebe
commit dbe9a8c969
2 changed files with 20 additions and 1 deletions

View File

@ -491,7 +491,7 @@ namespace QtPrivate {
template <typename, typename, typename, typename> struct FunctorCall;
template <int... II, typename... SignalArgs, typename R, typename Function>
struct FunctorCall<IndexesList<II...>, List<SignalArgs...>, R, Function> {
static void call(Function f, void **arg) {
static void call(Function &f, void **arg) {
f((*reinterpret_cast<typename RemoveRef<SignalArgs>::Type *>(arg[II+1]))...), ApplyReturnValue<R>(arg[0]);
}
};

View File

@ -147,6 +147,7 @@ private slots:
void qmlConnect();
void exceptions();
void noDeclarativeParentChangedOnDestruction();
void mutableFunctor();
};
struct QObjectCreatedOnShutdown
@ -6420,6 +6421,24 @@ void tst_QObject::noDeclarativeParentChangedOnDestruction()
#endif
}
struct MutableFunctor {
int count;
MutableFunctor() : count(0) {}
int operator()() { return ++count; }
};
void tst_QObject::mutableFunctor()
{
ReturnValue o;
MutableFunctor functor;
QCOMPARE(functor.count, 0);
connect(&o, &ReturnValue::returnInt, functor);
QCOMPARE(emit o.returnInt(0), 1);
QCOMPARE(emit o.returnInt(0), 2); // each emit should increase the internal count
QCOMPARE(functor.count, 0); // but the original object should have been copied at connect time
}
// Test for QtPrivate::HasQ_OBJECT_Macro
Q_STATIC_ASSERT(QtPrivate::HasQ_OBJECT_Macro<tst_QObject>::Value);
Q_STATIC_ASSERT(!QtPrivate::HasQ_OBJECT_Macro<SiblingDeleter>::Value);