Commit 6513fc88 authored by Eike Ziller's avatar Eike Ziller

runAsync: Allow calling member functions

Change-Id: Ide09b5585730fb3dcb4a18718a02a4d8351ef91e
Reviewed-by: Orgad Shaneh's avatarOrgad Shaneh <orgads@gmail.com>
parent 4b077921
......@@ -519,8 +519,25 @@ void blockingMapReduce(QFutureInterface<ReduceResult> futureInterface, const Con
futureInterface.reportFinished();
}
// TODO: Use universal references and std::forward to function when we require MSVC2015
// (MSVC2013 has a bug that std::thread does not move the copied arguments to the function call,
// which leads to compile errors with rvalue arguments)
template <typename ResultType, typename Function, typename Obj, typename... Args>
typename std::enable_if<std::is_member_pointer<typename std::decay<Function>::type>::value>::type
runAsyncImpl(QFutureInterface<ResultType> futureInterface, const Function &function, const Obj &obj, const Args&... args)
{
std::mem_fn(function)(obj, futureInterface, args...);
if (futureInterface.isPaused())
futureInterface.waitForResume();
futureInterface.reportFinished();
}
// TODO: Use universal references and std::forward to function when we require MSVC2015
// (MSVC2013 has a bug that std::thread does not move the copied arguments to the function call,
// which leads to compile errors with rvalue arguments)
template <typename ResultType, typename Function, typename... Args>
void runAsyncImpl(QFutureInterface<ResultType> futureInterface, const Function &function, const Args&... args)
typename std::enable_if<!std::is_member_pointer<typename std::decay<Function>::type>::value>::type
runAsyncImpl(QFutureInterface<ResultType> futureInterface, const Function &function, const Args&... args)
{
function(futureInterface, args...);
if (futureInterface.isPaused())
......@@ -556,6 +573,19 @@ QFuture<ReduceResult> mapReduce(const Container &container, const InitFunction &
return future;
}
/*!
The interface of \c {runAsync} is similar to the std::thread constructor and \c {std::invoke}.
The \a function argument can be a member function, an object with \c {operator()}, a
\c {std::function}, lambda, function pointer or function reference.
They need to take a \c {QFutureInterface<ResultType>&} as their first argument, followed by
other custom arguments which need to be passed to this function.
If \a function is a (non-static) member function, the first argument in \a args is expected
to be the object that the function is called on.
\sa std::thread
\sa std::invoke
*/
template <typename ResultType, typename Function, typename... Args>
QFuture<ResultType> runAsync(Function &&function, Args&&... args)
{
......
......@@ -68,6 +68,39 @@ public:
}
};
class MyObject {
public:
static void staticMember0(QFutureInterface<double> &fi)
{
fi.reportResults({0, 2, 1});
}
static void staticMember1(QFutureInterface<double> &fi, int n)
{
fi.reportResults(QVector<double>(n, 0));
}
void member0(QFutureInterface<double> &fi) const
{
fi.reportResults({0, 2, 1});
}
void member1(QFutureInterface<double> &fi, int n) const
{
fi.reportResults(QVector<double>(n, 0));
}
void memberString1(QFutureInterface<QString> &fi, const QString &s) const
{
fi.reportResult(s);
}
void memberString2(QFutureInterface<QString> &fi, QString s) const
{
fi.reportResult(s);
}
};
void tst_RunExtensions::runAsync()
{
// free function pointer
......@@ -122,6 +155,35 @@ void tst_RunExtensions::runAsync()
const Callable c{};
QCOMPARE(Utils::runAsync<double>(c, 2).results(),
QList<double>({0, 0}));
// static member functions
QCOMPARE(Utils::runAsync<double>(&MyObject::staticMember0).results(),
QList<double>({0, 2, 1}));
QCOMPARE(Utils::runAsync<double>(&MyObject::staticMember1, 2).results(),
QList<double>({0, 0}));
// member functions
const MyObject obj{};
QCOMPARE(Utils::runAsync<double>(&MyObject::member0, &obj).results(),
QList<double>({0, 2, 1}));
QCOMPARE(Utils::runAsync<double>(&MyObject::member1, &obj, 4).results(),
QList<double>({0, 0, 0, 0}));
QCOMPARE(Utils::runAsync<QString>(&MyObject::memberString1, &obj, s).results(),
QList<QString>({s}));
QCOMPARE(Utils::runAsync<QString>(&MyObject::memberString1, &obj, crs).results(),
QList<QString>({crs}));
QCOMPARE(Utils::runAsync<QString>(&MyObject::memberString1, &obj, cs).results(),
QList<QString>({cs}));
QCOMPARE(Utils::runAsync<QString>(&MyObject::memberString1, &obj, QString(QLatin1String("rvalue"))).results(),
QList<QString>({QString(QLatin1String("rvalue"))}));
QCOMPARE(Utils::runAsync<QString>(&MyObject::memberString2, &obj, s).results(),
QList<QString>({s}));
QCOMPARE(Utils::runAsync<QString>(&MyObject::memberString2, &obj, crs).results(),
QList<QString>({crs}));
QCOMPARE(Utils::runAsync<QString>(&MyObject::memberString2, &obj, cs).results(),
QList<QString>({cs}));
QCOMPARE(Utils::runAsync<QString>(&MyObject::memberString2, &obj, QString(QLatin1String("rvalue"))).results(),
QList<QString>({QString(QLatin1String("rvalue"))}));
}
QTEST_MAIN(tst_RunExtensions)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment