如何遍历mdspan?为何一维mdspan无法像span一样用范围for循环?
mdspan无法直接用范围for遍历的原因及解决方法
问题背景
使用std::span时可以直接通过范围for遍历元素:
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';
但改用Kokkos实现的std::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';
报错信息:
<source>:10:19: error: 'begin' was not declared in this scope 10 | for (auto x : ms) { | ^~
原因分析
mdspan的设计初衷是提供多维索引访问能力,而非作为可直接遍历的序列类型。标准mdspan(包括Kokkos的实现)既没有定义begin()/end()成员函数,也没有适配std::begin/std::end的重载。而范围for循环的底层逻辑是通过ADL(参数依赖查找)或std命名空间找到对应的begin和end迭代器,因此无法直接用范围for遍历mdspan。
遍历mdspan的方法
1. 一维mdspan遍历
方法一:转换为std::span
利用mdspan的data()获取底层数据指针,size()获取总元素数,构造std::span后即可用范围for:
std::vector vec = { 1, 2, 3, ..., 12 }; auto ms = std::mdspan(vec.data(), 12); for (auto x : std::span{ms.data(), ms.size()}) { std::cout << x << ' '; }
方法二:手动索引遍历
直接通过一维索引访问元素:
for (std::size_t i = 0; i < ms.extent(0); ++i) { std::cout << ms[i] << ' '; }
2. 多维mdspan遍历
方式一:扁平化遍历所有元素
同样转成std::span,直接遍历全部元素(按内存存储顺序):
std::vector vec = { 1, 2, ..., 12 }; // 2行6列的二维mdspan auto ms = std::mdspan(vec.data(), 2, 6); for (auto x : std::span{ms.data(), ms.size()}) { std::cout << x << ' '; }
方式二:按维度嵌套遍历
按照mdspan的维度层级,嵌套循环逐个访问元素,适合需要保留维度结构的场景:
// 二维mdspan示例 auto ms_2d = std::mdspan(vec.data(), 2, 6); for (std::size_t row = 0; row < ms_2d.extent(0); ++row) { for (std::size_t col = 0; col < ms_2d.extent(1); ++col) { std::cout << ms_2d[row, col] << ' '; } std::cout << '\n'; // 每行结束换行 }
// 三维mdspan示例(2x3x2) auto ms_3d = std::mdspan(vec.data(), 2, 3, 2); for (std::size_t i = 0; i < ms_3d.extent(0); ++i) { for (std::size_t j = 0; j < ms_3d.extent(1); ++j) { for (std::size_t k = 0; k < ms_3d.extent(2); ++k) { std::cout << ms_3d[i, j, k] << ' '; } std::cout << '\n'; } std::cout << "\n---\n"; }
方式三:使用Kokkos并行遍历(针对Kokkos mdspan)
如果是Kokkos的mdspan,还可以利用Kokkos的并行接口实现高效遍历,适合高性能计算场景:
// 二维mdspan并行遍历示例 Kokkos::parallel_for("traverse_mdspan", Kokkos::MDRangePolicy<Kokkos::Rank<2>>({0,0}, {ms_2d.extent(0), ms_2d.extent(1)}), [&](std::size_t row, std::size_t col) { // 处理ms_2d[row, col] std::cout << ms_2d[row, col] << ' '; });
内容的提问来源于stack exchange,提问作者einpoklum
相关产品推荐
相关产品推荐

