C++2c(C++26)標準ライブラリに追加される多次元部分ビューstd::submdspan
について。
namespace std {
template<
class T, class E, class L, class A,
class... SliceSpecifiers>
constexpr auto submdspan(
const mdspan<T, E, L, A>& src,
SliceSpecifiers... slices) -> ;
}
まとめ:
- 多次元ビュー
std::mdspan
(→id:yohhoy:20230303)から部分ビューを取り出す(slice)関数。
- 第2引数以降のスライス指定子リストにより、各次元のスライス方法(slicing)を指定する。
- 単一インデクス:単一値。指定次元に対するインデクスを固定し、次元数(rank)を1つ削減する。*1
- インデクス範囲:開始位置(begin)+終了位置(end)の組。
std::pair
や2要素std::tuple
等により*2、指定次元に対するインデクス範囲を取り出す。
- ストライド指定範囲:オフセット位置(offset)+要素数(extent)+ストライド(stride)の組。
std::strided_slice
により、指定次元に対してずらし幅指定したインデクス範囲を取り出す。
- 全選択:タグ値
std::full_extent
。指定次元をそのまま取り出す。
- “ストライド指定範囲” 用の
strided_slice
型は名前付き初期化(→id:yohhoy:20170820)をサポートする。
- 類似機能を提供するPython/numpyやMatlab/Fortranと異なり、変換元における終了位置(end)ではなく変換元における要素数(extent)による指定を行う。
- 例:
strided_slice{.offset=1, .extent=10, .stride=3}
またはstrided_slice{1, 10, 3}
- “インデクス範囲” および “ストライド指定範囲” で用いるインデクス値は、通常の値と整数定数の2種類をサポートする。*3
- 戻り値型
mdspan<T,E,L,A>
における多次元インデクス型E
の各次元要素数に影響を与える。
- 通常の値:整数リテラル(literal)*4を含む整数値。指定次元の要素数は実行時(
std::dynamic_extent
)に決定する。
- 整数定数:
std::integral_constant
互換の定数値*5。指定次元の要素数はコンパイル時に決定する。
- レイアウトポリシー
L
はC++標準ライブラリ提供メモリレイアウトのみサポートする。
std::layout_right
:同ポリシー型を維持できる場合はlayout_right
を利用。それ以外はlayout_stride
へ変換。
std::layout_left
:同ポリシー型を維持できる場合はlayout_left
を利用。それ以外はlayout_stride
へ変換。
std::layout_stride
:layout_stride
のまま。
- ユーザ定義レイアウトポリシーをサポートするには、カスタマイズポイント
submdspan_mapping
関数を実装する。カスタマイズポイント実装は必須要件ではないが、汎用のフォールバック実装は提供されない。
- 要素型
T
とアクセスポリシーA
は原則維持される。*6
スライス指定の例
int a[15];
std::ranges::iota(a, 1);
std::mdspan m0{a, std::extents<size_t, 3, 5>{}};
auto m1 = std::submdspan(m0, 1, std::full_extent);
auto m2 = std::submdspan(m0, std::full_extent, 2);
auto m3 = std::submdspan(m0, 1, 2);
auto m4d = std::submdspan(m0, std::pair{1,2}, std::tuple{1,3});
auto m5d = std::submdspan(m0,
std::strided_slice{.offset=0, .extent=3, .stride=2},
std::strided_slice{.offset=1, .extent=4, .stride=3});
template <int N>
constexpr auto Int = std::integral_constant<int, N>;
auto m4s = std::submdspan(m0,
std::pair{Int<1>,Int<2>}, std::tuple{Int<1>,Int<3>});
auto m5s = std::submdspan(m0,
std::strided_slice{.offset=0, .extent=Int<3>, .stride=Int<2>},
std::strided_slice{.offset=1, .extent=Int<4>, .stride=Int<3>});
レイアウトポリシー変換
int a[60] = ;
std::mdspan m0{a, std::extents<size_t, 3, 4, 5>{}};
auto m1 = std::submdspan(m0, 1, std::full_extent, std::full_extent);
auto m2 = std::submdspan(m0, 1, std::pair{1,2}, std::full_extent);
auto m3 = std::submdspan(m0, 1, 0, 2);
auto m4 = std::submdspan(m0, std::full_extent, 0, std::full_extent);
using Exts3x4x5 = std::extents<size_t, 3, 4, 5>;
std::array strides = {20, 1, 4};
auto mapping = std::layout_stride::mapping{Exts3x4x5{}, strides};
std::mdspan m0s{a, mapping};
auto m5 = std::submdspan(m0s, 0, std::full_extent, 0);
assert(m5.mapping().stride(0) == 1);
std::mdspan<int, std::extents<size_t, 4>> m5r{ m5 };
関連URL