我有三个方法,所有这些方法返回一个字符串,我想使用QtConcurrent运行所有这些方法,并将它们返回到单个列表或类似的东西. QtConcurrent :: mapped是理想的,因为它返回一个迭代器,但我只能运行一个方法.
在JavaScript中有promise.all([method_a,method_b,method_c]),它会自动将它们的返回合并到一个结果(迭代器)中.
在Qt怎么做?
解决方法:
由于您有几种方法可以调用,因此您可以将它们作为一系列仿函数传递给QtConcurrent :: mapped的第一个参数.映射函子是一个应用函子,它接受一个表示方法调用的函子并返回调用它的结果.
首先,让我们上课:
// https://github.com/KubaO/*n/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"); }
};
apply_t仿函数调用作为参数传递给它的方法:
template <class Method> struct apply_t {
using result_type = typename std::result_of_t<Method()>;
auto operator()(Method method) {
return method();
}
};
让我们可以方便地从一系列仿函数的类型中制作这样的涂抹器:
template <class Sequence, class A = apply_t<typename std::decay_t<Sequence>::value_type>>
A make_apply(Sequence &&) { return {}; }
为方便起见,我们还将有一个矢量发生器,其目的是: make_unique等:
template <class T> QVector<T> make_vector(std::initializer_list<T> init) {
return {init};
}
然后,问题变得相当简单.首先,我们创建一个将被调用的绑定方法的向量.然后我们将调用方法以及对它们进行操作的应用程序传递给QtConcurrent :: mapped. results()按顺序给出了方法调用的所有结果的列表.
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"}));
}
我们可以使用lambda而不是创建自定义的apply_t类,并将其包装以提供QtConcurrent :: mapped期望的result_type成员类型.有关包裹lambda的详细信息,请参阅this answer. rest of this answer提供了这种包装的例子.