• Class / Function / Type

      std::
    • Header file

      <>
    • Other / All

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

    履歴 編集

    class template
    <span>

    std::span

    namespace std {
      template <class ElementType, size_t Extent = dynamic_extent>
      class span;
    
    
      // viewコンセプトを有効化する
      template<class ElementType, size_t Extent>
      inline constexpr bool ranges::enable_view<span<ElementType, Extent>> = true;
    
      // borrowed_rangeコンセプトを有効化する
      template<class ElementType, size_t Extent>
      inline constexpr bool ranges::enable_borrowed_range<span<ElementType, Extent>> = true;
    }
    

    概要

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

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

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

    このクラスは、トリビアルコピー可能である(C++23)

    メモリ連続性

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

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

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

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

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

    静的な要素数をもつ場合、メンバ定数extentに要素数が保持されるため、メンバ変数として要素数を保持する必要がなく、領域を節約する最適化を行える。

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

    • 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
    at 参照範囲から、任意の位置の要素を取得する C++26
    front 参照範囲の先頭要素を取得する C++20
    back 参照範囲の末尾要素を取得する C++20
    data 参照範囲の先頭を指すポインタを取得する C++20

    イテレータ

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

    メンバ定数

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

    メンバ型

    名前 説明 対応バージョン
    element_type 要素型 ElementType C++20
    value_type CV修飾を除いた要素型 remove_cv_t<ElementType> C++20
    size_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 実装定義のイテレータ型。contiguous_iteratorrandom_access_iterator、constexprイテレータのモデルであり、コンテナのイテレータに対するすべての要件を満たす C++20
    reverse_iterator 逆順イテレータ reverse_iterator<iterator> C++20
    const_iterator 読み取り専用イテレータ std::const_iterator<iterator> C++23
    const_reverse_iterator 読み取り専用逆イテレータ std::const_iterator<reverse_iterator> C++23

    非メンバ関数

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

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

    処理系

    参照