提问人:einpoklum 提问时间:3/19/2023 最后编辑:einpoklum 更新时间:11/16/2023 访问量:493
如何迭代 mdspan?
How do I iterate an mdspan?
问:
因此,我决定使用 mdspan
而不是普通 span + 元素访问函数的组合。但是 - 我想用我的 mdspan 做的一件显而易见的事情是迭代它的元素。这就是我对 1D 跨度的处理方式:
std::vector vec = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
auto sp = std::span(vec.data(), 12);
for (auto x : sp) {
std::cout << x << ' ';
}
std::cout << '\n';
...但不是 's(使用 Kokkos 实现):mdspan
std::vector vec = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
auto ms = std::mdspan(vec.data(), 12);
for (auto x : ms) {
std::cout << x << ' ';
}
std::cout << '\n';
在 GodBolt(使用 GCC 中继)中尝试上述内容,我得到:
<source>:10:19: error: 'begin' was not declared in this scope
10 | for (auto x : ms) {
| ^~
所以,mdspans 似乎不是范围 - 即使它们是一维的(我什至希望迭代 2D 或 3D spans......怎么会这样?我该如何迭代它们?
答:
似乎您需要像普通 C 数组一样迭代一个:mdspan
std::vector vec = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
auto ms = std::experimental::mdspan(vec.data(), 12);
for (auto i : std::views::iota(0uz, ms.extent(0))) {
std::cout << ms[i] << ' ';
}
std::cout << '\n';
...多维跨度也是如此 - 就像多维 C 数组一样,但使用多参数:operator[]
std::vector vec = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
auto ms = std::experimental::mdspan(vec.data(), 2, 6);
for (auto r : std::views::iota(0uz, ms.extent(0))) {
for (auto c : std::views::iota(0uz, ms.extent(1))) {
std::cout << ms[r, c] << ' ';
// ... and note that ms[r][c] won't work! :-(
}
std::cout << '\n';
}
请参阅工作中的第二个示例:。GodBolt
现在,我不确定为什么你不能直接迭代 - 因为 肯定可以迭代。也许这个想法是为了强调内存中的顺序如何得不到保证?我想知道。mdspan
迭代器支持很早就从处理规范的论文转移到了另一篇论文(似乎没有任何进展)。mdspan
mdspan
被投票到 C++23 中的提案既不包含迭代器,也不允许创建对象切片(后者正在积极开发中)。mdspan
submdspans
mdspan
有一种解决方法可以创建一个可迭代的视图,该视图可以与使用 C++23 的算法一起使用:mdspan
std::ranges
views::cartesian_product
std::vector vec = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
auto ms = std::experimental::mdspan(vec.data(), 2, 6);
auto coeff_view =
std::views::cartesian_product(std::views::iota(0uz, ms.extent(0)),
std::views::iota(0uz, ms.extent(1))) |
std::views::transform([ms](const auto index) {
const auto [r, c] = index;
return ms[r, c];
});
std::cout << std::ranges::max(coeff_view) << '\n';
坏消息是,这种解决方法比直接对基础数据进行操作要慢得多,因为编译器似乎无法优化索引计算,如以下示例所示:https://godbolt.org/z/7a4T6KxY6。
另一件有用的事情是嵌入到类型中的布局信息。
当 a 是时,我的理解是,可以安全地假设基础数据是连续的,因此可以安全地转换为可以与算法一起使用的:mdspan
layout_type
mdspan
layout_right
data_handle()
std::span
std::ranges
template <typename Mdspan>
concept mdspan_specialization = std::same_as<
Mdspan, std::experimental::mdspan<
typename Mdspan::element_type, typename Mdspan::extents_type,
typename Mdspan::layout_type, typename Mdspan::accessor_type>>;
template <mdspan_specialization Mdspan>
requires(std::same_as<typename Mdspan::layout_type,
std::experimental::layout_right>)
auto to_span(const Mdspan ms) {
return std::span{ms.data_handle(), ms.size()};
}
评论
mdspan
。一致性在哪里?它是作为视图启动的;现在只是不满足视图的要求。
mdspan
。它仍然作为一种词汇表类型,允许使用来自不同来源的多维数据(想象一下,允许从、传递矩阵,所有这些都使用一个接口)。使用模板“元数据”,似乎仍然有实现良好性能的方法,只是不是开箱即用。也许人们会在第一个实现进入 std 库后立即找到更好的方法来处理这个问题。eigen
opencv
ipp
mdspan
for
mdspan
mdarray
mdspan
评论