QtConcurrent 与索引映射

Posted

技术标签:

【中文标题】QtConcurrent 与索引映射【英文标题】:QtConcurrent mapped with index 【发布时间】:2020-10-30 09:11:15 【问题描述】:

我想知道是否有一个选项也可以使用QtConcurrent::mapped(someVector, &someFunction))(也可以是filterfilteredmap、...)交出当前处理的索引

我想要什么:我想根据其中的当前索引对 someVector 中的元素做一些事情。但由于函数someFunction 只采用T 类型,它也用于QVector<T> vector

我做了什么:因为我需要这个,我创建了一个QVector<std::pair<int, T>> 并手动为元素创建了索引。

由于这需要更多空间并且不是一个好的解决方案,我想也许还有其他解决方案。

文档:https://doc.qt.io/qt-5/qtconcurrent-index.html

【问题讨论】:

如果一个元素需要知道它在容器中的编号,那就错了 @vladimir,我不同意。将容器作为元素的编号序列处理没有任何问题。这是一个很常见的模式,它的功能是like enumerate were added to Python。 【参考方案1】:

如果您的输入是QVector,您可以利用QVector 连续存储所有元素的事实。这意味着给定一个QVector v中的元素e的引用,那么e的索引可以通过以下方式获得:

std::ptrdiff_t idx = &e - &v.at(0);

以下是使用QtConcurrent::mapped的完整示例:

#include <iterator>
#include <numeric>
#include <type_traits>
#include <utility>

#include <QtCore>
#include <QtConcurrent>


// lambda functions are not directly usable in QtConcurrent::mapped, the
// following is a necessary workaround
// see https://***.com/a/49821973
template <class T> struct function_traits :
        function_traits<decltype(&T::operator())> ;

template <typename ClassType, typename ReturnType, typename... Args>
struct function_traits<ReturnType(ClassType::*)(Args...) const> 
   // specialization for pointers to member function
   using functor_type = ClassType;
   using result_type = ReturnType;
   using arg_tuple = std::tuple<Args...>;
   static constexpr auto arity = sizeof...(Args);
;

template <class Callable, class... Args>
struct CallableWrapper : Callable, function_traits<Callable> 
   CallableWrapper(const Callable &f) : Callable(f) 
   CallableWrapper(Callable &&f) : Callable(std::move(f)) 
;

template <class F, std::size_t ... Is, class T>
auto wrap_impl(F &&f, std::index_sequence<Is...>, T) 
   return CallableWrapper<F, typename T::result_type,
         std::tuple_element_t<Is, typename T::arg_tuple>...>(std::forward<F>(f));


template <class F> auto wrap(F &&f) 
   using traits = function_traits<F>;
   return wrap_impl(std::forward<F>(f),
                    std::make_index_sequence<traits::arity>, traits);


int main(int argc, char* argv[]) 
    QCoreApplication app(argc, argv);

    // a vector of numbers from 0 to 500
    QVector<int> seq(500, 0);
    std::iota(seq.begin(), seq.end(), 0);
    qDebug() << "input: " << seq;
    QFuture<int> mapped = QtConcurrent::mapped(seq, wrap([&seq](const int& x) 
        // the index of the element in a QVector is the difference between
        // the address of the first element in the vector and the address of
        // the current element
        std::ptrdiff_t idx = std::distance(&seq.at(0), &x);
        // we can then use x and idx however we want
        return x * idx;
    ));
    qDebug() << "output: " << mapped.results();

    QTimer::singleShot(100, &app, &QCoreApplication::quit);
    return app.exec();

有关相关讨论,请参阅this question。请注意,链接的问题有一个更清晰的答案,涉及使用 zip 和从 boost 计数迭代器(或者可能是它们的 C++20 范围对应物),但我认为这在QtConcurrent::map 时不会很好地与@987654331 配合使用@ 将序列分割成块,并将这些块分配给多个线程。

【讨论】:

以上是关于QtConcurrent 与索引映射的主要内容,如果未能解决你的问题,请参考以下文章

QtConcurrent blockingMappedReduced 与 MappedReduced

QtConcurrent 与成员函数

可以将 QtConcurrent 与 Ruby (mingw-32) 一起使用吗?

Qt多线程:QtConcurrent + QFuture + QFutureWatcher

是否可以将 QtConcurrent::run() 与类的函数成员一起使用

PySide/PyQt 中的 QtConcurrent