【问题标题】:Variadic template to proxy QtConcurrent::run functions代理 QtConcurrent::run 函数的可变参数模板
【发布时间】:2013-07-02 05:56:56
【问题描述】:

我希望创建一个可变参数模板函数,它位于 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'

非常感谢任何帮助。

【问题讨论】:

    标签: c++ qt variadic-templates qtconcurrent


    【解决方案1】:

    TaskManager.hpp(108) 是您拨打QtConcurrent::run 的线路。

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

    对于返回类型推导,您可能需要使用 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:

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

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

    【讨论】:

    • 感谢您指出 MSVC 错误。我已经实现了一个带有仿函数的重载:
    • template static auto Run(Functor functor) -> QFuture { // stuff} 这适用于 lambda。希望我在让返回类型正常工作方面遇到的困难也是由此引起的。
    • 您的评论“我想这不可能是一个智能指针”:它可能是一个 shared_ptr,这也可以工作并且可能更安全,以免我遗漏 deleteLater。谢谢。
    • 我不知道 Qt,deleteLater 让我有点困惑。一些框架有自己的方法来处理与shared_ptr 不兼容的引用计数,很高兴阅读 Qt 不是其中之一:)
    • deleteLater 几乎会在它返回到主事件循环时安排将其删除。我怀疑 shared_ptr 现在是否更安全,因为 connect 需要一个副本并在对象的持续时间内保留它,所以这是一个先有鸡还是先有蛋的问题。稍后删除将保留。
    猜你喜欢
    • 2021-10-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多