qt - QtConcurrent 与索引映射
问题描述
QtConcurrent::mapped(someVector, &someFunction))
我想知道是否有一个选项也可以使用(also filter
, filtered
, map
,...)移交当前处理的索引
我想要什么:我想根据其中的当前索引对 someVector 中的元素做一些事情。但由于该函数someFunction
仅采用T
也用于QVector<T> vector
.
我做了什么:因为我需要这个,我创建了一个QVector<std::pair<int, T>>
并手动创建了元素的索引。
由于这需要更多空间并且不是一个好的解决方案,我想也许还有另一种解决方案。
解决方案
如果您的输入是 a ,您可以利用连续存储所有元素QVector
的事实。QVector
这意味着给定对 a 中元素的引用e
,则可以通过以下方式获得QVector v
的索引: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://stackoverflow.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();
}
有关相关讨论,请参阅此问题。请注意,链接的问题有一个更清晰的答案,其中涉及使用 zip 和从 boost 计数迭代器(或者可能是它们的 C++20 范围对应物),但我认为QtConcurrent::map
当map
将序列切成块时这不会很好,并将这些块分配给多个线程。
推荐阅读
- reactjs - Create-react-app + TypeScript + CSS 模块:自动生成类型定义而不从 CRA 中弹出
- php - 如何仅在工作时间获得差异并排除额外时间和周末
- python - 按位置对字符串列表进行排序
- c++ - 为什么cs中地址的值总是偶数?
- md5 - Snowflake 在插入时是否存在 MD5 问题?
- python - 更新另一个条目小部件的基于条目小部件的内容
- javascript - 试图弄清楚为什么该功能不起作用
- c++ - C++ 中的私有继承可见性/访问
- spring - 如何使用 Openfeign 配置 Ribbon 来管理重试 - Spring?
- javascript - React Local Storage 和 Service Worker(重新上线时发送数据