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

履歴 編集

class template
<span>

std::span(C++20)

namespace std {
  template <class ElementType, size_t Extent = dynamic_extent>
  class span;
}

概要

std::spanは、シーケンスの所有権を保持せず、部分シーケンスを参照するクラスである。

このクラスは、std::vectorや配列といったコンテナから一部の連続的な要素を抽出し、それらの要素にのみなんらかの処理を適用する、という目的に使用できる。

文字列操作に特化したクラスとしてstd::basic_string_viewが定義されているが、こちらはメモリ連続性をもつあらゆるコンテナに適用できる。

メモリ連続性

このクラスの対象は、メモリの連続性を持つシーケンスである。例として、以下は対象のシーケンスである:

  • 組み込み配列
  • 要素を指すポインタと要素数の組
  • 先頭要素を指すポインタと、末尾要素の次を指すポインタの組
  • std::array
  • std::vector

メモリ連続性をもつクラスは、非メンバ関数data()によってポインタを取得でき、非メンバ関数size()によって要素数を取得できること。それらの関数は、ADLによって呼び出される。

静的な要素数と、動的な要素数

std::spanは、静的な要素数をもつ場合と、動的な要素数をもつ場合の両方をサポートする。それはテンプレートパラメータExtentによって表される。動的な要素数をもつ場合は、Extentとしてstd::dynamic_extentを指定する。動的な要素数は、std::vectorを参照したり、ポインタと要素数の組を扱ったり、参照範囲を動的に変更したりする場合に必要となる。

静的な要素数をもつ場合、メンバ定数extentに要素数が保持されるため、メンバ変数として要素数を保持する必要がなく、領域を節約する最適化を行える。また、静的な要素数をもつstd::span型に対しては、タプルインタフェースを適用できる。

テンプレートパラメータ制約

  • ElementTypeは、抽象型ではない完全オブジェクト型であること

備考

  • std::spanが参照する範囲[s.data(), s.data() + s.size())に含まれるポインタを無効にする操作を行った場合、std::spanオブジェクトのメンバ関数から返されるその範囲のポインタ、イテレータ、*this以外の参照が無効になる

メンバ関数

構築・破棄

名前 説明 対応バージョン
(constructor) コンストラクタ C++20
~span() = default; デストラクタ C++20
span& operator=(const span&) = default;
span& operator=(span&&) = default;
代入演算子 C++20

サブシーケンスの参照

名前 説明 対応バージョン
first 先頭N個の要素を参照するspanオブジェクトを取得する C++20
last 末尾N個の要素を参照するspanオブジェクトを取得する C++20
subspan 任意の位置からN個の要素を参照するspanオブジェクトを取得する C++20

領域

名前 説明 対応バージョン
size 参照している要素数を取得する C++20
size_bytes 参照している範囲のバイト数を取得する C++20
empty 参照している範囲が空かどうかを判定する C++20

要素アクセス

名前 説明 対応バージョン
operator[] 参照範囲から、任意の位置の要素を取得する C++20
front 参照範囲の先頭要素を取得する C++20
back 参照範囲の末尾要素を取得する C++20
data 参照範囲の先頭を指すポインタを取得する C++20

イテレータ

名前 説明 対応バージョン
begin 先頭要素を指すイテレータを取得する C++20
end 末尾要素の次を指すイテレータを取得する C++20
cbegin 先頭要素を指す読み取り専用イテレータを取得する C++20
cend 末尾要素の次を指す読み取り専用イテレータを取得する C++20
rbegin 末尾要素を指す逆順イテレータを取得する C++20
rend 先頭要素の前を指す逆順イテレータを取得する C++20
crbegin 末尾要素を指す読み取り専用逆順イテレータを取得する C++20
crend 先頭要素の前を指す読み取り専用逆順イテレータを取得する C++20

メンバ定数

名前 説明 対応バージョン
static constexpr index_type extent = Extent; 要素数。値が-1であれば動的な要素数、そうでなければ静的な固定要素数 C++20

メンバ型

名前 説明 対応バージョン
element_type 要素型 ElementType C++20
value_type CV修飾を除いた要素型 remove_cv_t<ElementType> C++20
index_type インデックスを表す符号なし整数型 size_t C++20
difference_type イテレータの差を表す符号付き整数型 ptrdiff_t C++20
pointer ポインタ型 element_type* C++20
const_pointer constポインタ型 const element_type* C++20
reference 参照型 element_type& C++20
const_reference const参照型 const element_type& C++20
iterator 実装定義のイテレータ型 C++20
const_iterator 実装定義の読み取り専用イテレータ C++20
reverse_iterator 逆順イテレータ reverse_iterator<iterator> C++20
const_reverse_iterator 読み取り専用逆イテレータ reverse_iterator<const_iterator> C++20

非メンバ関数

オブジェクトのバイト表現

名前 説明 対応バージョン
as_bytes 読み取り専用バイト列としてシーケンスを参照する C++20
as_writable_bytes 書込み可能なバイト列としてシーケンスを参照する C++20

タプルインタフェース

名前 説明 対応バージョン
tuple_size 要素数を取得する (class template) C++20
tuple_element i番目の要素型を取得する (class template) C++20
get 任意の位置の要素を取得する C++20

推論補助

名前 説明 対応バージョン
(deduction_guide) クラステンプレートの推論補助 C++20

基本的な使い方

#include <iostream>
#include <span>
#include <vector>
#include <utility>

// メモリ連続性をもつあらゆる範囲を出力する関数。
// std::spanオブジェクトはコピーで受け取るのが基本的な使い方
template <class T, std::size_t Extent>
void print(std::span<T, Extent> s)
{
  const char* delimiter = "";

  std::cout << '{';
  for (const T& x : s) {
    std::cout << std::exchange(delimiter, ",") << x;
  }
  std::cout << '}' << std::endl;
}

int main()
{
  std::vector<int> v = {1, 2, 3, 4, 5};
  int ar[] = {1, 2, 3, 4, 5};

  // spanに変換してコンテナ全体を出力
  print(std::span{v});

  // コンテナの一部の要素を出力
  print(std::span{v}.subspan(1, 3));

  // ポインタと要素数を指定した範囲を参照して、
  // 範囲for文を使用する
  print(std::span<int>{ar, 3});
}

出力

{1,2,3,4,5}
{2,3,4}
{1,2,3}

データのヘッダ情報とボディ情報をコピーなしで分割する

#include <iostream>
#include <span>
#include <vector>
#include <utility>

template <class T>
void process_header(std::span<T> s)
{
  const char* delimiter = "";

  std::cout << "[header] : ";
  for (int x : s) {
    std::cout << std::exchange(delimiter, ",") << x;
  }
  std::cout << std::endl;
}

template <class T>
void process_body(std::span<T> s)
{
  const char* delimiter = "";

  std::cout << "[body] : ";
  for (int x : s) {
    std::cout << std::exchange(delimiter, ",") << x;
  }
  std::cout << std::endl;
}

template <class T>
void f(std::span<T> s)
{
  std::size_t header_size = 3;
  process_header(s.first(header_size));
  process_body(s.last(s.size() - header_size));
}

int main()
{
  std::vector<int> data = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
  f(std::span{data});
}

出力

[header] : 1,2,3
[body] : 4,5,6,7,8,9,10

バージョン

言語

  • C++20

処理系

参照