• Class / Function / Type

      std::
    • Header file

      <>
    • Other / All

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

    履歴 編集

    function template
    <mdspan>

    std::submdspan

    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

    処理系

    関連項目

    参照