部分シーケンス関連の強化
C++ 23では、多次元のシーケンスのビューを生成できるstd::mdspanを利用できるようになりました。
部分シーケンスとは、配列やベクターなどの列(シーケンス)から順番を保ったまま、一部の要素だけを取り出してできる列のことです。元となるシーケンスに影響を与えずに安全にシーケンスを取り扱うことができ、数学/アルゴリズム分野で使われます。
1次元の部分シーケンスを生成するstd::span[C++ 20]
std::mdspanは、C++ 20で利用可能になったstd::spanの多次元版です。
std::spanは、配列やベクターなどシーケンスの全部あるいは一部を参照する部分シーケンスを生成するクラスです。冒頭の説明のように、もとのシーケンスに影響を与えずに部分的なシーケンスとして利用できます。
#include <iostream>
#include <vector>
#include <span>
…略…
vector<int> arr = {1, 2, 3, 4, 5};
span<int> sp(arr.begin() + 1, arr.begin() + 4); (1)
cout << "Partial span: ";
for (int val : sp) { (2)
cout << val << " ";
}
cout << endl; // Partial span: 2 3 4
ここでは、イテレータペアから部分シーケンスを生成するコンストラクタを使用しています(1)。span型は(2)のように独立したシーケンスのように扱うことができます。
行列演算や画像処理に最適な多次元配列ビューstd::mdspan[C++ 23]
C++ 23からは、多次元のシーケンス例えば2次元配列のビューを生成できるstd::mdspanを利用できるようになりました。
#include <mdspan>
…略…
vector<int> data = {1, 2, 3, 4, 5, 6}; (1)
mdspan<int, extents<size_t, 2, 3>> md2d(data.data()); (2)
cout << "2D mdspan (2x3):" << endl;
for (size_t i = 0; i < 2; ++i) {
for (size_t j = 0; j < 3; ++j) {
cout << md2d[i, j] << " "; (3)
}
cout << endl;
// 2D mdspan (2x3):2D mdspan (2x3):
// 1 2 3
// 4 5 6
}
mdspanクラスの機能は、spanのようなシンプルな部分シーケンスにとどまりません。以下のクラスをテンプレートパラメータに指定することで、単なる部分シーケンスを超えたビューの機能を提供します。
- ElementType:要素の型
- Extents:多次元配列の次元数(rank)と要素数(extent)
- LayoutPolicy:インデックスと要素の位置の対応を指定
- AccessorPolicy:要素アクセス時の挙動を指定
この例では、vectorによって保持される6要素の配列(1)を、2×3の多次元配列とするビューを生成しています(2)。要素の型ElementTypeはintであり、Extentsクラスにより次元数は2、要素数は3を指定しています。コンストラクタはvectorのdata関数によりメモリ上の位置を受け取ります。
いったんビューが出来上がれば、第2回で紹介した多次元operator[]によって、(3)のように多次元配列としてアクセスすることが可能です。行列演算や、それを利用した画像処理などに有用でしょう。
