Qt::Concurrent 与成员函数映射

Qt::Concurrent mapped with a member function

我想使用 QtConcurrent::mapped() 功能,但是通过提供的 QtConcurrent examples 并试图找到一个可用的示例来扩展到我的使用一直很困难。

在示例中,Qt maps 仅针对静态函数,未使用成员函数(示例中发现了许多类似的映射变体,但未使用成员函数)。

问题:

QtConcurrent::map() 将函数应用于序列或迭代器 w/o 返回即 QFuture<void>。但是我希望返回结果,即来自成员函数的 QFuture<SomeStructOrType>

我想在 example/scenario 中使用它是 UI 应用程序中的密集工作负载,但一个简单的示例可能是:

class MainWindow : public QMainWindow {
     Q_OBJECT

  public:
     // The struct is to demonstrate a datatype more complex than int / QString
     struct IntStruct {
         int i;
     };

     MainWindow(QWidget* parent = nullptr);
     IntStruct doubleValue(IntStruct i);
     ~MainWindow();

private:
   Ui::MainWindow* ui;
   // To watch progress and act upon progress change
   QFutureWatcher<IntStruct> futureWatcher;

   // Member to keep track of mapped process
   QFuture<IntStruct> future;

   //...
}

实施是:

MainWindow::MainWindow(QWidget* parent)
     : QMainWindow(parent)
     , ui(new Ui::MainWindow)
{
     ui->setupUi(this);

     // Input Sequence/Iterator to perform doubleValue function on
     QList<IntStruct> intList = QList<IntStruct>();
     for (int i = 0; i < 1000; i++) {
         IntStruct s;
         s.i = qrand();
         intList.append(s);
     }

     // Watch future and report on result ready (process a result when done)
     connect(&futureWatcher, &QFutureWatcher<IntStruct>::resultReadyAt, this, [intList](int index){
         qDebug() << QString("[index = %1] value = %2").arg(QString::number(index), QString::number(intList.at(index).i));
     });

     //typedef IntStruct (MainWindow::*doubleValueFunction)(IntStruct);
     //doubleValueFunction memberFunction = this->doubleValue;             // this->doubleValue error: reference to non-static member function must be called ???

     // Run future - this doubleValue function should be a pointer to an instance function, how to do so?         
     future = QtConcurrent::mapped(intList, &MainWindow::doubleValue);
     futureWatcher.setFuture(future);
}

// Some complex member function
MainWindow::IntStruct MainWindow::doubleValue(MainWindow::IntStruct i)
{
    i.i *= i.i;
    return i;
}

我知道 QtConcurrent 允许 lambda,但是我需要使用成员函数。

我还尝试使用一个指向当前实例的指针和 lambda,但它给了我一个 schpiel 错误,你可以找到 here

 future = QtConcurrent::mapped(intList, [this](IntStruct &i){
     this->doubleValue(i);
 });

TL;DR 所以基本上,我如何将 QtConcurrent::mapped() 与成员函数一起使用(最好是非 lambda 版本)?


赏金问题更新

一些额外信息:

这显示在屏幕上

我尝试编译时的错误日志:

..\ThreadTester\mainwindow.cpp: In constructor 'MainWindow::MainWindow(QWidget*)':
..\ThreadTester\mainwindow.cpp:27:69: error: no match for 'operator=' (operand types are 'QFuture<MainWindow::IntStruct>' and 'QFuture<void>')
      future = QtConcurrent::mapped(intList, &MainWindow::doubleValue);
                                                                     ^
In file included from F:\Qt\Qt5.13.1.13.1\mingw73_32\include\QtCore/QFuture:1:0,
                 from ..\ThreadTester\thread.h:10,
                 from ..\ThreadTester\mainwindow.h:6,
                 from ..\ThreadTester\mainwindow.cpp:1:
F:\Qt\Qt5.13.1.13.1\mingw73_32\include\QtCore/qfuture.h:59:7: note: candidate: QFuture<MainWindow::IntStruct>& QFuture<MainWindow::IntStruct>::operator=(const QFuture<MainWindow::IntStruct>&)
 class QFuture
       ^~~~~~~
F:\Qt\Qt5.13.1.13.1\mingw73_32\include\QtCore/qfuture.h:59:7: note:   no known conversion for argument 1 from 'QFuture<void>' to 'const QFuture<MainWindow::IntStruct>&'
F:\Qt\Qt5.13.1.13.1\mingw73_32\include\QtCore/qfuture.h:59:7: note: candidate: QFuture<MainWindow::IntStruct>& QFuture<MainWindow::IntStruct>::operator=(QFuture<MainWindow::IntStruct>&&)
F:\Qt\Qt5.13.1.13.1\mingw73_32\include\QtCore/qfuture.h:59:7: note:   no known conversion for argument 1 from 'QFuture<void>' to 'QFuture<MainWindow::IntStruct>&&'
In file included from F:\Qt\Qt5.13.1.13.1\mingw73_32\include/QtConcurrent/qtconcurrentfilterkernel.h:48:0,
                 from F:\Qt\Qt5.13.1.13.1\mingw73_32\include\QtConcurrent/qtconcurrentfilter.h:47,
                 from F:\Qt\Qt5.13.1.13.1\mingw73_32\include\QtConcurrent/QtConcurrent:8,
                 from ..\ThreadTester\thread.h:11,
                 from ..\ThreadTester\mainwindow.h:6,
                 from ..\ThreadTester\mainwindow.cpp:1:
F:\Qt\Qt5.13.1.13.1\mingw73_32\include/QtConcurrent/qtconcurrentmapkernel.h: In instantiation of 'QtConcurrent::ThreadEngineStarter<T> QtConcurrent::startMapped(const Sequence&, Functor) [with T = void; Sequence = QList<MainWindow::IntStruct>; Functor = QtConcurrent::MemberFunctionWrapper1<MainWindow::IntStruct, MainWindow, MainWindow::IntStruct>]':
F:\Qt\Qt5.13.1.13.1\mingw73_32\include\QtConcurrent/qtconcurrentmap.h:132:88:   required from 'QFuture<typename QtPrivate::MapResultType<void, MapFunctor>::ResultType> QtConcurrent::mapped(const Sequence&, MapFunctor) [with Sequence = QList<MainWindow::IntStruct>; MapFunctor = MainWindow::IntStruct (MainWindow::*)(MainWindow::IntStruct); typename QtPrivate::MapResultType<void, MapFunctor>::ResultType = void]'
..\ThreadTester\mainwindow.cpp:27:69:   required from here
F:\Qt\Qt5.13.1.13.1\mingw73_32\include/QtConcurrent/qtconcurrentmapkernel.h:237:71: error: could not convert 'QtConcurrent::startThreadEngine(ThreadEngine*) [with ThreadEngine = QtConcurrent::SequenceHolder1<QList<MainWindow::IntStruct>, QtConcurrent::MappedEachKernel<QList<MainWindow::IntStruct>::const_iterator, QtConcurrent::MemberFunctionWrapper1<MainWindow::IntStruct, MainWindow, MainWindow::IntStruct> >, QtConcurrent::MemberFunctionWrapper1<MainWindow::IntStruct, MainWindow, MainWindow::IntStruct> >; typename ThreadEngine::ResultType = MainWindow::IntStruct]()' from 'QtConcurrent::ThreadEngineStarter<MainWindow::IntStruct>' to 'QtConcurrent::ThreadEngineStarter<void>'
     return startThreadEngine(new SequenceHolderType(sequence, functor));
                                                                       ^
F:\Qt\Qt5.13.1.13.1\mingw73_32\include/QtConcurrent/qtconcurrentmapkernel.h: In instantiation of 'bool QtConcurrent::MappedEachKernel<Iterator, MapFunctor>::runIteration(Iterator, int, QtConcurrent::MappedEachKernel<Iterator, MapFunctor>::T*) [with Iterator = QList<MainWindow::IntStruct>::const_iterator; MapFunctor = QtConcurrent::MemberFunctionWrapper1<MainWindow::IntStruct, MainWindow, MainWindow::IntStruct>; QtConcurrent::MappedEachKernel<Iterator, MapFunctor>::T = MainWindow::IntStruct]':
..\ThreadTester\mainwindow.cpp:36:1:   required from here
F:\Qt\Qt5.13.1.13.1\mingw73_32\include/QtConcurrent/qtconcurrentmapkernel.h:175:17: error: no match for call to '(QtConcurrent::MemberFunctionWrapper1<MainWindow::IntStruct, MainWindow, MainWindow::IntStruct>) (const MainWindow::IntStruct&)'
         *result = map(*it);
In file included from F:\Qt\Qt5.13.1.13.1\mingw73_32\include\QtConcurrent/qtconcurrentfilter.h:48:0,
                 from F:\Qt\Qt5.13.1.13.1\mingw73_32\include\QtConcurrent/QtConcurrent:8,
                 from ..\ThreadTester\thread.h:11,
                 from ..\ThreadTester\mainwindow.h:6,
                 from ..\ThreadTester\mainwindow.cpp:1:
F:\Qt\Qt5.13.1.13.1\mingw73_32\include/QtConcurrent/qtconcurrentfunctionwrappers.h:132:14: note: candidate: T QtConcurrent::MemberFunctionWrapper1<T, C, U>::operator()(C&, U) [with T = MainWindow::IntStruct; C = MainWindow; U = MainWindow::IntStruct]
     inline T operator()(C &c, U u)
              ^~~~~~~~
F:\Qt\Qt5.13.1.13.1\mingw73_32\include/QtConcurrent/qtconcurrentfunctionwrappers.h:132:14: note:   candidate expects 2 arguments, 1 provided
mingw32-make[1]: *** [Makefile.Debug:1117: debug/mainwindow.o] Error 1
mingw32-make[1]: *** Waiting for unfinished jobs....
mingw32-make[1]: Leaving directory 'C:/Users/CybeX/QtProjects/build-ThreadTester-Desktop_Qt_5_13_1_MinGW_32_bit-Debug'
mingw32-make: *** [Makefile:38: debug] Error 2

对我来说完全没有意义的是 mapped() returns 某些数据类型 U。如果我将 QFuture<IntStruct> 更改为 QFuture<void>,每个人都会很高兴,但是我无法收集到任何违背 mapped() 函数目的的结果。

你必须使用 std::bind:

#include <functional>

# ....

future = QtConcurrent::mapped(intList,
                              std::bind(&MainWindow::doubleValue,
                                        this,
                                        std::placeholders::_1));