Есть шаблонная функция:
template <typename Function , typename ...Args>
auto exceptionWrapper (Object *obj, Function&& function, Args&& ...args)-> decltype((obj->*function)(std::forward<Args>(args)...))
{
try
{
QScopedPointer<Object> tempObj(new Object(obj->getSomeData()));
return (tempObj->*function)(std::forward<Args>(args)...);
}
catch(std::exception& e)
{
...
}
}
Есть другая функция, которая ее вызывает через qtConcurrent::run
:
template <typename Function , typename ...Args, typename CallBack>
void Object::callAsync(Object *obj,Function&& query,CallBack&& callBack, Args&& ...args)
{
using ReturnValue = decltype(exceptionWrapper(obj, query, std::forward<Args>(args)...));
QFutureWatcher<ReturnValue> watcher;
connect(&watcher, &QFutureWatcher <ReturnValue>::finished, callBack);
QFuture<ReturnValue> futureValue = QtConcurrent::run(exceptionWrapper, obj, query, std::forward<Args>(args)...);
watcher.setFuture(futureValue);
}
При попытке вызова в коде:
Object object = new Object();
Object::callAsync(object, Object::objFcn, [](){qDebug()<<"qq";}, arg1, arg2);
Возникает ошибка:
ошибка: no matching function for call to 'run(<unresolved overloaded function type>, BOKZDatabase*&, AngleOrientData (BOKZDatabase::*&)(const QString&, const QString&, const QString&, const QString&, int), const QString&, const QString&, const QString&, const QString&, const int&)'
QFuture<ReturnValue> futureValue = QtConcurrent::run(exceptionWrapper, db, query, std::forward<Args>(args)...);
^
Что я упустил?
UPD: В случае явного указания параметров шаблона ошибка о неопределенном типе функции остается:
template <typename Function , typename ...Args, typename CallBack>
void Object::callAsync (Object *obj,Function&& query,CallBack&& callBack, Args&& ...args)
{
using ReturnValue = decltype(exceptionWrapper(obj, query, args...));
QFutureWatcher<ReturnValue> watcher;
connect(&watcher, &QFutureWatcher <ReturnValue>::finished, callBack);
QFuture<ReturnValue> futureValue = QtConcurrent::run(exceptionWrapper <Function, Args...>, obj, std::forward<Function>(query), std::forward<Args>(args)...);
watcher.setFuture(futureValue);
}
UPD 2. Минимальный пример:
class Object
{
public:
int sum(int a, int b)
{
return a+b;
}
};
template <typename Function , typename ...Args>
auto fcn (Object *object, Function&& function, Args&& ...args)-> decltype ((object->*function)(std::forward<Args>(args)...))
{
return (object->*function)(std::forward<Args>(args)...);
}
template <typename Function , typename ...Args>
void callAsync(Object *object,Function&& function, Args&& ...args)
{
QtConcurrent::run(fcn <Function, std::forward<Args...>>, object, function, std::forward<Args>(args)...);
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Object* obj = new Object();
callAsync(obj, Object::sum, 5, 6);
return a.exec();
}
exceptionWrapper
сам по себе не является функцией, но неким шаблоном функции, поэтому мы не можем никуда его передать — мы можем передавать лишь что-то конкретное, а не абстракцию, коей является шаблон.
Таким образом, нам нужно конкретизировать (инстанциировать) exceptionWrapper
прежде чем передавать его в QtConcurrent::run
. Здесь встаёт другая проблема: с какими аргументами инстанциировать? Т.к. exceptionWrapper
использует пробрасывающую ссылку (forwarding reference), идёт расчёт на то, что аргументы будут выводиться при вызове функции, но у нас ситуация иная — мы явно задаём аргументы шаблона. Конечно, мы всё равно получаем нужный результат таким вызовом:
QtConcurrent::run(exceptionWrapper<Function, Args...>, obj, std::forward<Function>(query), std::forward<Args>(args)...);
Происходит это из-за того, что у нас в callAsync
пробрасывающая ссылка, а в exceptionWrapper
, в результате явной инстанциации, у нас rvalue-ссылка, и применяя правила C++ по свертке ссылок мы на выходе имеем то, что и ожидали: будет инстанциирована правильная, т.е. ожидаемая нами функция exceptionWrapper
. К примеру, если мы рассмотрим минимальный пример, из Вашего дополненного вопроса, то при таком вызове:
int var = 5;
callAsync(obj, &Object::sum, 7, var);
Будет сгенерирована функция exceptionWrapper
с такой сигнатурой: int (Object *,int (Object::* )(int,int),int &&,int &)
— как раз то, что и ожидалось. Но в этом кроется другая проблема. Мы работаем с конкурентной средой и пытаемся вызвать метод Qt, который потенциально выполнит наш метод в другом потоке. Но, чтобы выполнить метод в другом потоке, он вынужден скопировать (либо же переместить, если умеет) аргументы и сохранить их до того времени, когда можно будет вызвать нашу функцию.
Сохраняя наши аргументы, Qt отбрасывает их изначальный тип и впоследствии, при передаче их в нашу функцию, все наши аргументы станут lvalue. Но в сигнатуре нашей функции есть int&&
, который является rvalue-ссылкой и lvalue не может быть передано туда! Поэтому, нам придётся отказаться от пробрасывающих ссылок в exceptionWrapper
— они там не нужны и только мешают, там нужен обычный const &
.
В результате получим такое решение:
template <typename Function , typename ...Args>
auto fcn(Object *object, Function function, const Args& ...args)
{
return (object->*function)(args...);
}
template <typename Function , typename ...Args>
void callAsync(Object *object, Function&& function, Args&& ...args)
{
QtConcurrent::run(fcn<Function, Args...>, object, function,
std::forward<Args>(args)...);
}
Конечно, можно подумать и над альтернативными решениями, но этот ответ уже и так довольно длинный получился.
Виртуальный выделенный сервер (VDS) становится отличным выбором
Нужно построить алгоритм с временем работы O(mn)На вход подается список положительных целых чисел a_1, a_2,
Добрый день! Много прочитал в интернете статей на эту тему и не до конца понял как этот метод реализуетсяМожет есть блок схема или псевдокод...