I have three methods and all of them returns a string, I want to run all of them using QtConcurrent
and get their return into a single list or something like that. QtConcurrent::mapped
is ideal as it returns an iterator but I can only run one method at time.
In JavaScript there's promise.all([method_a, method_b, method_c])
, it will automatically merge their return into a single result (iterator).
How to do that in Qt?
-
1Use a QVector and append, if the return is a blocking call. If not `QtConcurrent` is wrong, use QThread and send the value back as a merged single value when all 3 values are available in the thread. There is no syntax to merge all returns in a single value what you would know from Perl or Javascript. – user3606329 Apr 13 '18 at 09:00
-
@user3606329 Of course there is a merge operation, and `QFuture` provides it already via the `results()` method! – Kuba hasn't forgotten Monica Apr 13 '18 at 18:00
-
@ Kuba Ober: yes I know about `QFuture::results()`. The OP wanted probably an one-liner to merge the results of 3 QtConcurrent calls and showed the promise.all method from Javascript as reference. – user3606329 Apr 13 '18 at 20:25
4 Answers
Since there's no built in way to do that, you can work out a class on your own to keep futures together and return a collection of results when all tasks completed. The only limitation, here, is due to the strongly typed nature of c++: each future returned by QtConcurrent::run
holds the called function result, the type of which is given at compile time, as the QFuture
template parameter. What if the return types of the called functions differ from each other? In the example I provide, they all return the same type, but I think one could use QVariant
for that mean and get away with it.
In a promise.h:
#ifndef PROMISE_H
#define PROMISE_H
#include <QtConcurrent/QtConcurrentRun>
#include <QFutureWatcher>
class PromiseInterface
{
public:
virtual ~PromiseInterface() = default;
virtual void finished(int id) = 0;
};
class Watcher : public QObject
{
Q_OBJECT
int _id;
PromiseInterface * _promise;
public slots:
void finished()
{
_promise->finished(_id);
deleteLater();
}
public:
Watcher(int id, PromiseInterface * promise)
: _id(id),
_promise(promise)
{}
};
template <typename T>
class Promise : public PromiseInterface
{
friend class Watcher;
void finished(int id) override
{
_resolved++;
_results[id] = _watchers[id]->result();
delete _watchers[id];
if(_resolved == _results.size())
{
if(_callback != nullptr)
{
_callback(_results);
}
}
}
QList<QFutureWatcher<T> *> _watchers;
QVector<T> _results;
void (*_callback)(QVector<T>);
int _resolved;
public:
Promise(QList<QFuture<T>> futures)
{
_resolved = 0;
_callback = nullptr;
_results.resize(futures.size());
int i=0;
for(auto f : futures)
{
QFutureWatcher<T> * watcher = new QFutureWatcher<T>();
watcher->setFuture(f);
QObject::connect(watcher, &QFutureWatcher<T>::finished, new Watcher(i++, this), &Watcher::finished);
_watchers.append(watcher);
}
}
void then(void (*callback)(QVector<T>)) { _callback = callback; }
};
#endif // PROMISE_H
The Promise
class is a class template with a single template parameter that matches the one of QFuture
. The observed futures are passed in the constructor, while the then
method accepts a the completion callback as its only argument.
The Watcher
class provides a slot to catch QFutureWatcher::finished' signals. Each instance knows the promise object through a pointer to its
PromiseInterfaceand will call
finished` from the slot, passing in the id of the future that completed.
When all futures finished, the callback function is called with the vector of results passed in.
In a very simple usage example, we can execute this function concurrently:
#include <unistd.h>
int f(int r) { sleep(1); return r;}
and pass this callback to the promise then
:
void callback(QVector<int> results)
{
qDebug() << results;
}
Our main:
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QList<QFuture<int>> futures = {
QtConcurrent::run(&f, 1),
QtConcurrent::run(&f, 2),
QtConcurrent::run(&f, 3)
};
Promise<int> promise(futures);
promise.then(callback);
return a.exec();
}
After about a second, this is the expected output:
QVector(1, 2, 3)
Just in case one wonders why I put in three classes, instead of making Promise
extend QObject
directly, and implement the finished
slot itself: Qt is not letting me do that. When the Q_OBJECT
macro is added to a class template, an explicit compiler error will prompt: Template classes not supported by Q_OBJECT.

- 9,807
- 2
- 22
- 35
Since you have several methods to call, you can pass them as a sequence of functors as the first argument to QtConcurrent::mapped
. The mapping functor would be an apply
functor that takes a functor representing the method call and returns the result of invoking it.
First, let's have our class:
// https://github.com/KubaO/stackoverflown/tree/master/questions/concurrent-combine-49802153
#include <QtConcurrent>
#include <functional>
#include <initializer_list>
#include <type_traits>
class Cls {
public:
QString method1() const { return QStringLiteral("10"); }
QString method2() const { return QStringLiteral("20"); }
QString method3() const { return QStringLiteral("30"); }
};
The apply_t
functor invokes the method passed to it as an argument:
template <class Method> struct apply_t {
using result_type = typename std::result_of_t<Method()>;
auto operator()(Method method) {
return method();
}
};
Let's make it convenient to make such applicators from the type of a sequence of functors to be called:
template <class Sequence, class A = apply_t<typename std::decay_t<Sequence>::value_type>>
A make_apply(Sequence &&) { return {}; }
For convenience, we'll also have a vector generator in the spirit of e.g. make_unique
, etc.:
template <class T> QVector<T> make_vector(std::initializer_list<T> init) {
return {init};
}
Then, the problem becomes fairly simple. First, we make a vector of bound methods that will be called. Then we pass the methods to call, as well as the applicator to operate on them, to QtConcurrent::mapped
. The results()
gives a list of all results of the method calls, in sequence.
int main() {
Cls obj;
auto const methods = make_vector({
std::bind(&Cls::method1, &obj),
std::bind(&Cls::method2, &obj),
std::bind(&Cls::method3, &obj)
});
QFuture<QString> result =
QtConcurrent::mapped(methods, make_apply(methods));
Q_ASSERT((result.results() == QStringList{"10", "20", "30"}));
}
Instead of making a custom apply_t
class, we could use a lambda, wrapped to provide the result_type
member type that QtConcurrent::mapped
expects. See this answer for details of wrapping the lambda. The rest of this answer provides examples of such wrapping.

- 95,931
- 16
- 151
- 313
-
Is `result_type` for? _These function objects can be used to add state to a function call_.,how make of this sentence? – Crawl.W Jun 01 '20 at 09:02
-
@Crawl.W `result_type` is the type returned by `Method`. In order to be used in some circumstances, functors (callable objects) need to have a `result_type` type member, or an equivalent type in a trait class. – Kuba hasn't forgotten Monica Jun 02 '20 at 00:40
The method you're looking for is QFuture::results()
:
QList<T> QFuture::results() const
Returns all results from the future. If the results are not immediately available, this function will block and wait for them to become available.
Expanding from Qt's own QtConcurrent::mapped
example:
QImage scaled(const QImage &image)
{
return image.scaled(100, 100);
}
QList<QImage> images = ...;
QList<QImage> thumbnails = QtConcurrent::mapped(images, scaled).results();

- 305
- 1
- 9
-
You didn't understand what I meant, I want to call three methods at the same time, imagine that there's `scaled1`, `scaled2`, `scaled3` and not only `scaled`. and get the result of all of them like the `promise.all` from javascript. – Mr Gisa Apr 12 '18 at 17:29
-
I know AsyncFuture
is a c++ library that converts calls into a QFuture type and uses it like a Promise object in Javascript (Combine multiple futures with different type into a single future object). unfortunately i never used it! but there are details on this reference Qt Blog Multithreaded Programming with Future & Promise

- 4,452
- 10
- 23
- 47