Commit dcf09b00 authored by Eike Ziller's avatar Eike Ziller

runAsync: Support functions wrapped in reference_wrapper

Change-Id: I2dbb793239d432a1316dadb81beee564cc858eaa
Reviewed-by: default avatarTobias Hunger <tobias.hunger@theqtcompany.com>
parent 640d1269
......@@ -53,6 +53,12 @@ struct functionTraits<Result(*)(Args...)> : public functionTraits<Result(Args...
{
};
// const function pointer
template <typename Result, typename... Args>
struct functionTraits<Result(* const)(Args...)> : public functionTraits<Result(Args...)>
{
};
// member function
template <typename Type, typename Result, typename... Args>
struct functionTraits<Result(Type::*)(Args...)> : public functionTraits<Result(Type&,Args...)>
......@@ -65,6 +71,18 @@ struct functionTraits<Result(Type::*)(Args...) const> : public functionTraits<Re
{
};
// const pointer to member function
template <typename Type, typename Result, typename... Args>
struct functionTraits<Result(Type::* const)(Args...)> : public functionTraits<Result(Type&,Args...)>
{
};
// const pointer to const member function
template <typename Type, typename Result, typename... Args>
struct functionTraits<Result(Type::* const)(Args...) const> : public functionTraits<Result(Type&,Args...)>
{
};
// TODO: enable lvalue and rvalue ref member function later (MSVC 2015?)
//// lvalue ref member function
//template <typename Type, typename Result, typename... Args>
......
......@@ -168,8 +168,6 @@ struct resultType<Function &&> : public resultType<Function>
{
};
// work around bug in MSVC 2015 where a reference_wrapper has a call operator even if the wrapped
// object doesn't
template <typename Function>
struct resultType<std::reference_wrapper<Function>> : public resultType<Function>
{
......@@ -282,7 +280,7 @@ template <typename ResultType, typename Function, typename... Args,
typename = typename std::enable_if<
!std::is_member_pointer<typename std::decay<Function>::type>::value
>::type>
void runAsyncImpl(QFutureInterface<ResultType> futureInterface, Function &&function, Args&&... args)
void runAsyncMemberDispatch(QFutureInterface<ResultType> futureInterface, Function &&function, Args&&... args)
{
runAsyncArityDispatch(std::integral_constant<bool, (functionTraits<Function>::arity > 0)>(),
futureInterface, std::forward<Function>(function), std::forward<Args>(args)...);
......@@ -293,14 +291,30 @@ template <typename ResultType, typename Function, typename Obj, typename... Args
typename = typename std::enable_if<
std::is_member_pointer<typename std::decay<Function>::type>::value
>::type>
void runAsyncImpl(QFutureInterface<ResultType> futureInterface, Function &&function, Obj &&obj, Args&&... args)
void runAsyncMemberDispatch(QFutureInterface<ResultType> futureInterface, Function &&function, Obj &&obj, Args&&... args)
{
// Wrap member function with object into callable
runAsyncImpl(futureInterface,
MemberCallable<Function>(std::forward<Function>(function), std::forward<Obj>(obj)),
MemberCallable<typename std::decay<Function>::type>(std::forward<Function>(function), std::forward<Obj>(obj)),
std::forward<Args>(args)...);
}
// cref to function/callable
template <typename ResultType, typename Function, typename... Args>
void runAsyncImpl(QFutureInterface<ResultType> futureInterface,
std::reference_wrapper<Function> functionWrapper, Args&&... args)
{
runAsyncMemberDispatch(futureInterface, functionWrapper.get(), std::forward<Args>(args)...);
}
// function/callable, no cref
template <typename ResultType, typename Function, typename... Args>
void runAsyncImpl(QFutureInterface<ResultType> futureInterface,
Function &&function, Args&&... args)
{
runAsyncMemberDispatch(futureInterface, std::forward<Function>(function),
std::forward<Args>(args)...);
}
/*
AsyncJob is a QRunnable that wraps a function with the
arguments that are passed to it when it is run in a thread.
......
......@@ -43,6 +43,7 @@ private slots:
#endif
void threadPriority();
void runAsyncNoFutureInterface();
void crefFunction();
};
void report3(QFutureInterface<int> &fi)
......@@ -487,6 +488,75 @@ void tst_RunExtensions::runAsyncNoFutureInterface()
QList<double>({4}));
}
void tst_RunExtensions::crefFunction()
{
// free function pointer with future interface
auto fun = &report3;
QCOMPARE(Utils::runAsync(std::cref(fun)).results(),
QList<int>({0, 2, 1}));
// lambda with future interface
auto lambda = [](QFutureInterface<double> &fi, int n) {
fi.reportResults(QVector<double>(n, 0));
};
QCOMPARE(Utils::runAsync(std::cref(lambda), 3).results(),
QList<double>({0, 0, 0}));
// std::function with future interface
const std::function<void(QFutureInterface<double>&,int)> funObj = [](QFutureInterface<double> &fi, int n) {
fi.reportResults(QVector<double>(n, 0));
};
QCOMPARE(Utils::runAsync(std::cref(funObj), 2).results(),
QList<double>({0, 0}));
// callable with future interface
const Callable c{};
QCOMPARE(Utils::runAsync(std::cref(c), 2).results(),
QList<double>({0, 0}));
// member functions with future interface
auto member = &MyObject::member0;
const MyObject obj{};
QCOMPARE(Utils::runAsync(std::cref(member), &obj).results(),
QList<double>({0, 2, 1}));
// free function pointer without future interface
bool value = false;
auto voidFun = &voidFunction;
Utils::runAsync(std::cref(voidFun), &value).waitForFinished();
QCOMPARE(value, true);
auto oneFun = &one;
QCOMPARE(Utils::runAsync(std::cref(oneFun)).results(),
QList<int>({1}));
// lambda without future interface
auto lambda2 = [](int n) -> double {
return n + 1;
};
QCOMPARE(Utils::runAsync(std::cref(lambda2), 3).results(),
QList<double>({4}));
// std::function
const std::function<double(int)> funObj2 = [](int n) {
return n + 1;
};
QCOMPARE(Utils::runAsync(std::cref(funObj2), 2).results(),
QList<double>({3}));
// callable without future interface
const CallableWithoutQFutureInterface c2{};
Utils::runAsync(std::cref(c2), &value).waitForFinished();
QCOMPARE(value, true);
// member functions without future interface
const MyObjectWithoutQFutureInterface obj2{};
auto member2 = &MyObjectWithoutQFutureInterface::member0;
value = false;
Utils::runAsync(std::cref(member2), &obj2, &value).waitForFinished();
QCOMPARE(value, true);
}
QTEST_MAIN(tst_RunExtensions)
#include "tst_runextensions.moc"
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