最終更新日時(UTC):
が更新

履歴 編集

function template
<mdspan>

std::submdspan(C++26)

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_typeExtents::index_type、変数sub_map_offsetsubmdspan_mapping(src.mapping(), slices...)の結果としたとき、

事前条件

効果

以下と等価

基本的な使い方

#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);
}

出力

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));
}

出力

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>);
}

出力

バージョン

言語

  • C++26

処理系

関連項目

参照