用于代理QtConcurrent :: run函数的变量模板

时间:2013-07-02 05:56:56

标签: c++ qt variadic-templates qtconcurrent

我希望创建一个可变参数模板函数,该函数位于QtConcurrent :: run函数前面,它执行一些操作,然后传递参数。

QtConcurrent :: run大量超载 - 请查看qtconcurrentrun.h

是否可以创建一个我可以调用的可变参数模板函数,它将传递给QtConcurrent :: run?这就是我到目前为止所做的:

template <typename returnT, typename... Args>
static auto Run(Args&&... args) -> QFuture<returnT>
{
     // Do Stuff

     // Now call through to start the task
     QFuture<returnT> future = QtConcurrent::run(std::forward<Args>(args)...);

     QFutureWatcher<void>* futureWatcher = new QFutureWatcher<void>(); //A QFutureWatcher<void> is special, see QFutureWatcher QT docs.
     futureWatcher->setFuture(future);
     QObject::connect(futureWatcher, &QFutureWatcher<void>::finished, [=]() { 
        // Do stuff
        futureWatcher->deleteLater();
     });
     return future;
  }

我正在努力弄清楚如何推断返回类型,所以我将returnT作为单独的模板参数。当使用:

调用时,这不会编译(VS2012 Nov CTP)
Tasking::TaskManager::Run<void>([&]() { while (stopTask == false); });

顶部错误消息为:

1> error C2065: '<lambda_86e0f4508387a4d4f1dd8316ce3048ac>' : undeclared identifier
1>          Implementation\TaskingTests\TaskManagerTests.cpp(31) : see reference to function template instantiation 'QFuture<void> Tasking::TaskManager::Run<void,TaskManagerTests::WaitsForTaskTest::<lambda_86e0f4508387a4d4f1dd8316ce3048ac>>(TaskManagerTests::WaitsForTaskTest::<lambda_86e0f4508387a4d4f1dd8316ce3048ac> &&)' being compiled
1>C:\tkbt\Launch2.0.0\ICDE\IceLibrary\Implementation\Tasking/TaskManager.hpp(108): error C2974: 'std::forward' : invalid template argument for '_Ty', type expected
1>          C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\include\type_traits(1780) : see declaration of 'std::forward'
1>          C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\include\type_traits(1774) : see declaration of 'std::forward'
1>C:\tkbt\Launch2.0.0\ICDE\IceLibrary\Implementation\Tasking/TaskManager.hpp(108): error C2780: 'QFuture<T> QtConcurrent::run(const Class *,T (__cdecl Class::* )(Param1,Param2,Param3,Param4,Param5) const,const Arg1 &,const Arg2 &,const Arg3 &,const Arg4 &,const Arg5 &)' : expects 7 arguments - 0 provided
1>          c:\qt\qt5.0.2\5.0.2\msvc2012_64\include\qtconcurrent\qtconcurrentrun.h(333) : see declaration of 'QtConcurrent::run'

任何帮助都非常感激。

1 个答案:

答案 0 :(得分:1)

猜测 TaskManager.hpp(108)是您拨打QtConcurrent::run的行。

您遇到的似乎是this MSVC bug。简而言之,可变参数模板无法在MSVC中转发lambdas。在这种情况下,您可能必须使用oldscool仿函数,或者提供非变量重载来支持lambdas,可能是前几个参数。如果我不得不猜测我认为QtConcurrent::run的第一个参数必须是一个函数而其他参数是它的参数,这意味着你永远不会在没有参数的情况下调用Run。您可以重写函数模板,为函数和函数参数的参数包提供一个固定的“normal”参数。

对于返回类型推导,您可能希望使用decltype。一起看起来像这样:

template <class F, class... Args>
static auto Run(F&& f, Args&&... args) 
  -> decltype(QtConcurrent::run(std::forward<F>(f), std::forward<Args>(args)...))
{
  auto future = QtConcurrent::run(std::forward<F>(f), std::forward<Args>(args)...);

  //I suppose this can not be a smart pointer?
  auto futureWatcher = new QFutureWatcher<void>(); 

  futureWatcher->setFuture(future);
  QObject::connect(futureWatcher, &QFutureWatcher<void>::finished, [=]() { 
    // Do stuff
    futureWatcher->deleteLater();
  });
  return future;
}

这样,lambda将被传递给普通的模板参数F,它应该可以转发,即错误不应该这样发生。

更新:如果QtConcurrent::run 立即为您提供正确的返回类型,您可以在函数及其参数上使用decltype:< / p>

static auto Run(F&& f, Args&&... args) 
  -> QtFuture<decltype(f(std::forward<Args>(args)...))>

也许您需要在decltype中添加一些std::remove_referencestd::remove_const以获得正确的未来类型。