如何从连续内存位置直接获取C++ mdspan的张量索引?
从mdspan连续内存位置反向获取张量索引的实现方案
你已经实现了从mdspan张量索引获取连续内存位置的功能,现在需要反向操作:给定内存偏移位置,直接获取对应的张量索引,无需手动进行算术计算。目前标准C++23的std::mdspan并没有内置类似indices_from_pos的方法,但可以利用mdspan的布局映射工具自己实现一个通用解决方案。
原代码示例
#include <https://raw.githubusercontent.com/kokkos/mdspan/single-header/mdspan.hpp> #include <vector> #include <algorithm> #include <iostream> #include <ranges> int main(){ std::vector vec = {1, 2, 3, 4, 5, 6, 7, 88, 9, 10, 11, 12}; auto ms = std::mdspan(vec.data(), 2, 6); //已知张量索引,获取连续内存中的位置 { const int position = std::distance(vec.data(), &ms[1, 3]); std::cout << position << '\n'; } //已知连续内存中的位置,如何直接获取张量索引? { const int position = 9; //我希望避免手动进行算术计算,有没有类似 auto [i, j] = ms.indices_from_pos(position) 的方法? } }
实现通用的indices_from_pos函数
下面的模板函数支持任意维度的mdspan,兼容默认的行优先(layout_right)、列优先(layout_left)等连续内存布局:
#include <tuple> #include <mdspan> #include <utility> // 内部实现:按维度序列计算每个索引 template<class Mdspan, std::size_t... Is> auto indices_from_pos_impl(const Mdspan& ms, typename Mdspan::index_type pos, std::index_sequence<Is...>) { auto mapping = ms.mapping(); auto strides = mapping.strides(); typename Mdspan::index_type remaining = pos; return std::make_tuple( [&]<std::size_t I>() { auto idx = remaining / strides[I]; remaining %= strides[I]; return idx; }.template operator()<Is>()... ); } // 对外接口:自动推导维度序列 template<class Mdspan> auto indices_from_pos(const Mdspan& ms, typename Mdspan::index_type pos) { using indices_seq = std::make_index_sequence<Mdspan::rank()>; return indices_from_pos_impl(ms, pos, indices_seq{}); }
在主函数中使用
修改原代码的对应部分,即可直接获取张量索引:
//已知连续内存中的位置,获取张量索引 { const int position = 9; auto [i, j] = indices_from_pos(ms, position); std::cout << "对应的张量索引:(" << i << ", " << j << ")\n"; // 输出 (1, 3) }
说明
- 该函数通过mdspan的
mapping()获取布局的strides(各维度的内存步长),反向计算每个维度的索引,完全避免手动硬编码算术逻辑。 - 支持任意维度的mdspan,只要布局是连续内存的(非稀疏布局)。
- 注意:参数
pos必须是相对于mdspan起始地址的偏移量(即std::distance(ms.data_handle(), 目标地址)的结果),如果是全局内存地址,需要先转换为相对偏移。
内容的提问来源于stack exchange,提问作者Ludovic Aubert
相关产品推荐
相关产品推荐

