namespace std {
template<
class ElementType,
class Extents,
class LayoutPolicy,
class AccessorPolicy,
class... SliceSpecifiers>
constexpr auto submdspan(
const mdspan<ElementType, Extents, LayoutPolicy, AccessorPolicy>& src,
SliceSpecifiers... slices) -> see below;
}
概要
多次元配列ビューmdspan
と各次元からの要素取り出し(スライス)方式を指定して、メモリブロックに対する新しい多次元配列ビューmdspan
を取得する。
スライス指定
各次元からの要素取り出し方式は、下記の4種類をサポートする。
スライス指定子リストslices...
にインデクス値指定が含まれる場合、戻り値の次元数(rank)は元の多次元配列ビューに対してインデクス値指定した次元数だけ削減される。
- インデクス値指定 : 整数値。指定次元に対する多次元インデクス値を固定する。
- インデクス範囲指定 : インデクス・ペア互換型の値。開始位置(begin)と終了位置(end)で表現される半開区間から要素群を取り出す。
- ストライド・スライス指定 :
std::strided_slice
の値。オフセット(offset)と要素数(extent)とストライド幅(stride)で指定される要素群を取り出す。 - 全要素指定 :
std::full_extent
。指定次元の全要素を取り出す。
カスタマイゼーションポイント
submdspan
関数によりmdspan
から部分ビューを取り出すには、変換元のレイアウトマッピング型がカスタマイゼーションポイントsubmdspan_mapping
を実装している必要がある。
テンプレートパラメータ制約
sizeof...(slices)
がExtents::rank()
と等しく、かつ- 評価されない文脈において式
submdspan_mapping(src.mapping(), slices...)
が妥当な式であること。
適格要件
説明用の型index_type
をExtents::index_type
、変数sub_map_offset
をsubmdspan_mapping(src.mapping(), slices...)
の結果としたとき、
- 型
decltype(submdspan_mapping(src.mapping(), slices...))
がsubmdspan_mapping_result
の特殊化であり、 is_same_v<remove_cvref_t<decltype(sub_map_offset.mapping.extents())>, decltype(submdspan_extents(src.mapping(), slices...))>
がtrue
、かつsrc.extents()
の各次元インデクスk
において、S_k
をSliceSpecifiers
のk
番目の型としたき、下記いずれかのうち1つだけを満たすこと。- 型
S_k
がconvertible_to<index_type>
のモデル - 型
S_k
がindex-pair-like<index_type>
のモデル is_convertible_v<S_k, full_extent_t>
がtrue
- 型
S_k
がstrided_slice
の特殊化
- 型
事前条件
src.extents()
の各次元インデクスk
において、S_k
をSliceSpecifiers
のk
番目の型、s_k
をslices
のk
番目の値としたとき、下記を全て満たすこと。- 型
S_k
がstrided_slice
の特殊化のときs_k.extent == 0
、またはs_k.stride > 0
0
≤first_<index_type, k>(slices...)
≤last_<k>(src.extents(), slices...)
≤src.extent(k)
- 型
sub_map_offset.mapping.extents() == submdspan_extents(src.mapping(), slices...)
がtrue
、かつsub_map_offset.mapping.extents()
の多次元インデクス値を表す任意の整数パックI
に対して、sub_map_offset.mapping(I...) + sub_map_offset.offset == src.mapping()(src-indices(array{I...}, slices...))
がtrue
であること。
効果
以下と等価
auto sub_map_offset = submdspan_mapping(src.mapping(), slices...);
return mdspan(src.accessor().offset(src.data_handle(), sub_map_offset.offset),
sub_map_offset.mapping,
AccessorPolicy::offset_policy(src.accessor()));
例
基本的な使い方
#include <mdspan>
#include <numeric>
#include <print>
#include <string_view>
// 2次元配列ビュー(Matrix)の要素表示
template <class T, class E, class L, class A>
void print_mat(std::string_view name, const std::mdspan<T, E, L, A>& mat)
{
static_assert(mat.rank() == 2);
std::println("{}:", name);
for (size_t i = 0; i < mat.extent(0); ++i) {
for (size_t j = 0; j < mat.extent(1); ++j) {
std::print(" {:2}", mat[i, j]);
}
std::println("");
}
}
// 1次元配列ビュー(Vector)の要素表示
template <class T, class E, class L, class A>
void print_vec(std::string_view name, const std::mdspan<T, E, L, A>& mat)
{
static_assert(mat.rank() == 1);
std::println("{}:", name);
for (size_t i = 0; i < mat.extent(0); ++i) {
std::print(" {:2}", mat[i]);
}
std::println("");
}
int main()
{
int arr[20];
std::ranges::iota(arr, 1);
// 4x5要素の2次元配列ビュー
using Ext2D = std::dextents<size_t, 2>;
std::mdspan mat{arr, Ext2D{4, 5}};
print_mat("mat", mat);
// インデクス値指定+全要素指定(2次元→1次元)
auto row1 = std::submdspan(mat, 1, std::full_extent);
print_vec("mat[1,M]", row1);
auto col2 = std::submdspan(mat, std::full_extent, 2);
print_vec("mat[N,2]", col2);
// 単一要素の取り出し(2次元→0次元)
auto elem = std::submdspan(mat, 1, 2);
std::println("mat[1,2]:\n {:2}", elem[]);
// インデクス範囲指定
auto submat = std::submdspan(mat, std::pair{1,3}, std::pair{1,4});
print_mat("submat", submat);
// ストライド・スライス指定
auto strided = std::submdspan(mat,
std::strided_slice{.offset=1, .extent=3, .stride=2},
std::strided_slice{.offset=0, .extent=5, .stride=2});
print_mat("strided", strided);
}
62
#include <mdspan>
#include <numeric>
#include <print>
#include <string_view>
// 2次元配列ビュー(Matrix)の要素表示
template <class T, class E, class L, class A>
void print_mat(std::string_view name, const std::mdspan<T, E, L, A>& mat)
{
static_assert(mat.rank() == 2);
std::println("{}:", name);
for (size_t i = 0; i < mat.extent(0); ++i) {
for (size_t j = 0; j < mat.extent(1); ++j) {
std::print(" {:2}", mat[i, j]);
}
std::println("");
}
}
出力
mat:
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16 17 18 19 20
mat[1,M]:
6 7 8 9 10
mat[N,2]:
3 8 13 18
mat[1,2]:
8
submat:
7 8 9
12 13 14
strided:
6 8 10
16 18 20
静的要素数mdspanの生成
#include <concepts>
#include <mdspan>
#include <numeric>
#include <print>
// 整数定数型
template <int N>
constexpr auto Int = std::integral_constant<int, N>{};
int main()
{
int arr[20];
std::ranges::iota(arr, 1);
// 静的要素数 4x5 の2次元配列ビュー
std::mdspan mat{arr, std::extents<size_t, 4, 5>{}};
// 動的要素数 2x3 の2次元配列部分ビューを取り出し
auto submat_dyn = std::submdspan(mat,
std::pair{1, 3},
std::strided_slice{.offset=0, .extent=5, .stride=2});
static_assert(std::same_as<decltype(submat_dyn)::extents_type, std::dextents<size_t, 2>>);
std::println("submat_dyn {}x{}", submat_dyn.extent(0), submat_dyn.extent(1));
// 静的要素数 2x3 の2次元配列部分ビューを取り出し
auto submat_2x3 = std::submdspan(mat,
std::pair{Int<1>, Int<3>},
std::strided_slice{.offset=0, .extent=Int<5>, .stride=Int<2>});
// (strided_slice::offset は戻り値型に影響を与えない)
static_assert(std::same_as<decltype(submat_2x3)::extents_type, std::extents<size_t, 2, 3>>);
std::println("submat_2x3 {}x{}", submat_2x3.extent(0), submat_2x3.extent(1));
}
33
static_assert(std::same_as<decltype(submat_2x3)::extents_type, std::extents<size_t, 2, 3>>);
#include <concepts>
#include <mdspan>
#include <numeric>
#include <print>
// 整数定数型
template <int N>
constexpr auto Int = std::integral_constant<int, N>{};
int main()
{
int arr[20];
std::ranges::iota(arr, 1);
// 静的要素数 4x5 の2次元配列ビュー
std::mdspan mat{arr, std::extents<size_t, 4, 5>{}};
// 動的要素数 2x3 の2次元配列部分ビューを取り出し
出力
submat_dyn 2x3
submat_2x3 2x3
レイアウトマッピング互換性
#include <mdspan>
int main()
{
int arr[6] = {1, 2, 3, 4, 5, 6};
// 3x2要素の2次元配列ビュー(行優先レイアウト)
std::mdspan mat{arr, std::extents<size_t, 3, 2>{}};
static_assert(std::same_as<decltype(mat)::layout_type, std::layout_right>);
// 1 2
// 3 4
// 5 6
// 行優先レイアウト std::layout_right を維持
auto row0 = std::submdspan(mat, 0, std::full_extent);
// 1 2
auto row12 = std::submdspan(mat, std::pair{1,3}, std::full_extent);
// 3 4
// 5 6
static_assert(std::same_as<decltype(row0)::layout_type, std::layout_right>);
static_assert(std::same_as<decltype(row12)::layout_type, std::layout_right>);
// 汎用ストライド指定レイアウト std::layout_stride に変換
auto col1 = std::submdspan(mat, std::full_extent, 1);
// 2 4 6
auto row02 = std::submdspan(mat,
std::strided_slice{.offset=0, .extent=3, .stride=2},
std::full_extent);
// 1 2
// 5 6
static_assert(std::same_as<decltype(col1)::layout_type, std::layout_stride>);
static_assert(std::same_as<decltype(row02)::layout_type, std::layout_stride>);
}
34
static_assert(std::same_as<decltype(row02)::layout_type, std::layout_stride>);
#include <mdspan>
int main()
{
int arr[6] = {1, 2, 3, 4, 5, 6};
// 3x2要素の2次元配列ビュー(行優先レイアウト)
std::mdspan mat{arr, std::extents<size_t, 3, 2>{}};
static_assert(std::same_as<decltype(mat)::layout_type, std::layout_right>);
// 1 2
// 3 4
// 5 6
// 行優先レイアウト std::layout_right を維持
auto row0 = std::submdspan(mat, 0, std::full_extent);
// 1 2
auto row12 = std::submdspan(mat, std::pair{1,3}, std::full_extent);
// 3 4
出力
バージョン
言語
- C++26
処理系
- Clang: ??
- GCC: ??
- ICC: ??
- Visual C++: ??