QtConcurrent::mapped() with a member function complaining about error: no match for 'operator=' (operand types are 'QFuture<MainWindow::IntStruct>' and 'QFuture<void>')
-
I want to use the
QtConcurrent::mapped()
function, but going through the QtConcurrent examples provided and trying to find a usable example to extend to my use has been difficult.In the examples, Qt maps to static functions only, no member functions are used (many simliar mapped variations are found in the examples, but no member functions are used).
The problem:
QtConcurrent::map()
applies a function to a Sequence or Iterator w/o returning i.e.QFuture<void>
. However I wish to have the results returned i.e.QFuture<SomeStructOrType>
from a member function.The example/scenario I want to use it in is an intensive workload in a UI application, but a simplied example could be:
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; //... }
The implementation being:
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; }
I am aware that QtConcurrent allows lambdas, however I need to utilize a member function instead.
I also attempted using a pointer to the current instance with a lambda, but it gave my a schpiel of errors, which you can find here.
future = QtConcurrent::mapped(intList, [this](IntStruct &i){ this->doubleValue(i); });
TL;DR
So basically, how can I use QtConcurrent::mapped() with a member function (in preferably a non-lambda version)?
Some extra information:
This is shown on screen
Error log when I try to compile:
..\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\5.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\5.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\5.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\5.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\5.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\5.13.1\mingw73_32\include/QtConcurrent/qtconcurrentfilterkernel.h:48:0, from F:\Qt\Qt5.13.1\5.13.1\mingw73_32\include\QtConcurrent/qtconcurrentfilter.h:47, from F:\Qt\Qt5.13.1\5.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\5.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\5.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\5.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\5.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\5.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\5.13.1\mingw73_32\include\QtConcurrent/qtconcurrentfilter.h:48:0, from F:\Qt\Qt5.13.1\5.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\5.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\5.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
What does not make sense to me at all is
mapped()
returns some datatype U. If I changed theQFuture<IntStruct>
toQFuture<void>
, everyone is happy, but I cannot gather any results which defeats the purpose of themapped()
function in the first place. -
@CybeX A written in documentation ==> https://doc.qt.io/qt-5/qtconcurrentmap.html#concurrent-map
When using a modifier function, the futur will return
void
, not the parameter type.
You have to change you function signature to:MainWindow::IntStruct doubleValue(MainWindow::IntStruct &i);
-
So I have 2 options available to me. I could use:
- map() which changes values in-place (in the
intList
QList<IntStruct
I pass in) with aQFuture<IntStruct>
or - mapped() which uses a
QFuture<void>
and requires a call toQFuture::result()
(which is blocking if no results are ready, I suggest connecting aQFutureWatcher<>::onResultReady()
to it).
to use member functions, I can either
- leave my
QFuture<void>
as shown in the docs by @KroMignon. It is not explicitly said, but it should be extracted from the provided example - an easy thing to miss. - Alternatively, I can use use
std::bind
while keeping myQFuture<IntStream>
future = QtConcurrent::map(intList, std::bind( &MainWindow::doubleValue, this, std::placeholders::_1 ) );
- map() which changes values in-place (in the
-
@VRonin
Quite right - infact 101% correct.However, and you can correct me if I am wrong, but these mapped functions can be used for more than just transforming the datatype into another datatype. It does not always need to be 'instance based'. Let me explain what I mean (and what my thought process is)
In Java (lang level 8), there is the introduction of the Stream API with a bunch of additional features such as lambdas, etc. One particularly useful example is something like
List<SomeClass> list = ... list.stream().map(o -> o.someMember).filter(o -> o.value < 2).collect(Collectors.asList());
Now this simply takes an object (of type List), and runs a mapping functions (returning a stream object) and running a filter function on it (returning another stream object) followed by collecting all objects into a list.
Now, my intention, specifically in this case is to utilize the filter & map functions similarly, but due to its design (QtConcurrent functions), I am breaking these functions up with signals (and slots) everywhere.
This isn't part of the question, but for my own curiosity, if one had to mimik functions like this above, is there a...shorter way of doing the same thing rather than
QFuture<SomeStruct> future = ... QFutureWatcher<SomeStruct> ... connect( //futurewatcher signal started with whatever) connect( //futurewatcher signal finished with whatever) QFutureWatcher::setFuture(future) ...
just for one part of the function (i.e. mapping or filter)