QtConcurrent::map() with member function = can not compile

multithreading, qt, qtconcurrent

Solution

To be able to call a pointer-to-member, you need, in addition to that functions formal arguments, an instance of that class (the `this` pointer that you get inside member functions).

There are two ways to handle this: create a simple functor to wrap the call, or use a lambda.

The functor would look like this:

struct AddWrapper {
  MainWindow *instance;
  AddWrapper(MainWindow *w): instance(w) {}
  void operator()(QString const& data) {
    instance->add(data);
  }
};

And you'd use it like:

AddWrapper wrap(this);
QtConcurrent::map(list, wrap);

(Careful with the lifetime of that wrapper though. You could make that more generic - you could also store a pointer-to-member in the wrapper for instance, and/or make it a template if you want to reuse that structure for other types.)

If you have a C++11 compiler with lambdas, you can avoid all that boilerpalte:

QtConcurrent::map(list, [this] (QString const& data) { add(data); });

Note: I'm not sure how `QtConcurrent::MemberFunctionWrapper1` got involved in your example, I'm not seeing it here. So there might be a generic wrapper already in Qt for this situation, but I'm not aware of it.

Problem

My project is to create a small program which demonstrates the work of a search engine: indexing and returning result for arbitrary queries. I've done the work with the indexer part and now I want to improve it with indexing multiple files at once. The MainWindow class is here: ``` class MainWindow : public QMainWindow { Q_OBJECT ..... private: Indexer * indexer; QStringList fileList; .... void index(QStringList list); void add(const QString &filename); } ``` This is the implementation of `add` (`add` need to access `fileList` to avoid index the same files again, thus it can not be static method): ``` void MainWindow::add(const QString &filename) { if (!fileList.contains(filename)) { indexer->addDocument(filename.toStdString()); fileList.append(filename); qDebug() << "Indexed" << filename; emit updatedList(fileList); } } ``` The implement of `index` method is to receive a file lists and call `add` upon each file name: ``` void MainWindow::index(QStringList list) { .... QtConcurrent::map(list, &MainWindow::add); .... } ``` The error I receive when compiling these code is: ``` usr/include/qt4/QtCore/qtconcurrentmapkernel.h: In member function 'bool QtConcurrent::MapKernel<Iterator, MapFunctor>::runIteration(Iterator, int, void*) [with Iterator = QList<QString>::iterator, MapFunctor = QtConcurrent::MemberFunctionWrapper1<void, MainWindow, const QString&>]': ../search-engine/mainwindow.cpp:361:1: instantiated from here /usr/include/qt4/QtCore/qtconcurrentmapkernel.h:73:9: error: no match for call to '(QtConcurrent::MemberFunctionWrapper1<void, MainWindow, const QString&>) (QString&)' /usr/include/qt4/QtCore/qtconcurrentfunctionwrappers.h:128:7: note: candidate is: /usr/include/qt4/QtCore/qtconcurrentfunctionwrappers.h:138:14: note: T QtConcurrent::MemberFunctionWrapper1<T, C, U>::operator()(C&, U) [with T = void, C = MainWindow, U = const QString&] /usr/include/qt4/QtCore/qtconcurrentfunctionwrappers.h:138:14: note: candidate expects 2 arguments, 1 provided ``` I'm not really familiar with how QtConcurrent works, and the documentation doesn't provide much details about it. I really hope that someone here can help. Thanks in advance.

Original source