如何创建起始索引非0的std::mdspan以直接用原始维度值访问元素?
可以直接用
year, month, ZipCode访问的std::mdspan实现方案 当然可以,有两种主流实现方式,分别适配不同的C++版本:
方法一:C++23原生支持(使用std::strided_layout)
利用C++23引入的std::strided_layout,可以直接为每个维度指定起始索引偏移和元素步长,让mdspan直接识别原始的年份、月份、邮编数值:
#include <mdspan> #include <array> // 假设vec是已解析好的std::vector<int> auto vec = parse_binary_file(); // 定义各维度的范围:年份1913-2023(100个)、月份1-12(12个)、邮编20000-20999(1000个) using Extents = std::extents<std::size_t, 100, 12, 1000>; // 创建带偏移的布局:每个维度的起始索引、元素步长 auto layout = std::strided_layout<Extents>( std::array<std::size_t, 3>{1913, 1, 20000}, // 各维度的起始值 std::array<std::size_t, 3>{12 * 1000, 1000, 1} // 各维度的元素步长 ); // 构造支持直接索引的mdspan auto my_md_span = std::mdspan<int, Extents, decltype(layout)>(vec.data(), layout); // 直接使用原始数值访问 int count = my_md_span[1913, 1, 20000]; // 正确获取对应组合的居民数量
这种方式完全依赖C++23标准,需要编译器支持(如GCC 12+、Clang 15+、MSVC 2022+)。
方法二:兼容C++17及以上(封装轻量视图)
如果无法使用C++23,可以封装一个简单的包装类,自动处理索引偏移转换,同时保留mdspan的轻量特性:
#include <mdspan> #include <tuple> struct InhabitantsView { std::mdspan<int, std::extents<std::size_t, 100, 12, 1000>> inner_span; // 支持多参数调用(更直观) int& operator()(int year, int month, int zip_code) { return inner_span[year - 1913, month - 1, zip_code - 20000]; } // 支持tuple索引(可选) int& operator[](const std::tuple<int, int, int>& idx) { auto [year, month, zip] = idx; return inner_span[year - 1913, month - 1, zip - 20000]; } }; // 使用方式 auto original_span = std::mdspan(vec.data(), 100, 12, 1000); InhabitantsView my_view{original_span}; // 直接访问 int count = my_view(1913, 1, 20000); // 或用tuple索引 // int count = my_view[{1913, 1, 20000}];
这种方式兼容性更强,且不会带来额外性能开销,本质只是对原始mdspan的一层薄封装。
内容的提问来源于stack exchange,提问作者Porsche9II
相关产品推荐
相关产品推荐

