最終更新日時: 2026年05月18日 11時17分41秒 (JST)
Akira Takahashi が更新

履歴 編集

function
<span>

# std::span::コンストラクタ(C++20)

    constexpr span() noexcept;                                     // (1) C++20

    template <class It>
    constexpr explicit(extent != dynamic_extent)
      span(It first, size_type count);                             // (2) C++20

    template <class It, class End>
    constexpr explicit(extent != dynamic_extent)
      span(It first, End last);                                    // (3) C++20

    template <size_t N>
    constexpr span(
      type_identity_t<element_type> (&arr)[N]) noexcept;           // (4) C++20

    template <class T, size_t N>
    constexpr span(array<T, N>& arr) noexcept;                     // (5) C++20

    template <class T, size_t N>
    constexpr span(const array<T, N>& arr) noexcept;               // (6) C++20

    template <class R>
    constexpr explicit(extent != dynamic_extent)
      span(R&& r);                                                 // (7) C++20

    constexpr span(const span& other) noexcept = default;          // (8) C++20

    template <class OtherElementType, size_t OtherExtent>
    constexpr explicit(extent != dynamic_extent && OtherExtent == dynamic_extent)
      span(const span<OtherElementType, OtherExtent>& s) noexcept; // (9) C++20

## 概要

`span`オブジェクトを構築する。

- (1) : デフォルトコンストラクタ。空の`span`オブジェクトを構築する
- (2) : 参照範囲として先頭要素を指すイテレータと、そこからの要素数を指定して、それらの要素を参照する`span`オブジェクトを構築する
- (3) : 参照範囲として先頭要素を指すイテレータと、末尾要素の次を指すイテレータを指定して、それらの要素を参照する`span`オブジェクトを構築する
- (4) : 指定された組み込み配列の全体を参照する`span`オブジェクトを構築する
- (5) : 指定された非`const`左辺値参照の`std::array`の全体を参照する`span`オブジェクトを構築する
- (6) : 指定された`const`左辺値参照の`std::array`の全体を参照する`span`オブジェクトを構築する
- (7) : 指定された、メモリ連続性をもつイテレータを持つオブジェクトの要素全体を参照する`span`オブジェクトを構築する
- (8) : コピーコンストラクタ。`other`と同じ範囲を参照する`span`オブジェクトを構築する
- (9) : テンプレートパラメータの異なる`span`オブジェクトを変換する。以下のような変換ができる：
  - 静的な要素数をもつ`span`から動的な要素数をもつ`span`への変換。
  - 動的な要素数をもつ`span`同士の変換
  - `span<T>`から`span<const T>`への変換
  - バイト数が同じ暗黙の型変換が可能な要素型をもつ`span`同士の変換

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

- (1) :
  - `Extent == dynamic_extent || Extent == 0`が`true`であること
    - 値`-1`はオーバーフローによって正の最大値になるので`false`
- (2) :
  - 型 `U` を `std::remove_reference_t<std::iter_reference_t<It>>`とするとき
    - 型 `It` はコンセプト `std::contiguous_iterator` を満たしていること
    - `std::is_convertible_v<U(*)[], element_type(*)[]>` が `true` であること。(この制約の意図は、イテレータ参照型から `element_type` への修飾の変換のみを許可すること)
- (3) :
  - 型 `U` を `std::remove_reference_t<std::iter_reference_t<It>>`とするとき
    - 型 `It` はコンセプト `std::contiguous_iterator` を満たしていること
    - `std::is_convertible_v<U(*)[], element_type(*)[]>` が `true` であること。(この制約の意図は、イテレータ参照型から `element_type` への修飾の変換のみを許可すること)
    - 型 `End` はコンセプト `std::sized_sentinel_for<It>` を満たしていること
    - `std::is_convertible_v<End, size_t>` が `false`であること
- (4), (5), (6) :
  - `extent == dynamic_extent || N == extent`が`true`であること
  - `remove_pointer_t<decltype(data(arr))>`を型`U`であるとして、
    - `is_convertible_v<U(*)[], element_type(*)[]>`が`true`であること (この制約の意図は、配列の要素型から`element_type`へ、修飾の変換のみを許可すること)
- (7) :
  - 型 `U` を `std::remove_reference_t<std::iter_reference_t<R>>`とするとき
    - 型 `R` はコンセプト `std::ranges::contiguous_range` 及び `std::ranges::sized_range` を満たしていること
    - 型 `R` がコンセプト `std::ranges::borrowed_range` を満たすか、`std::is_const_v<element_type>` が`true`であること
    - `std::remove_cvref_t<R>`が`std::span`の特殊化ではないこと
    - `std::remove_cvref_t<R>`が`std::array`の特殊化ではないこと
    - `std::is_array_v<std::remove_cvref_t<R>>` が `false` であること
    - `std::is_convertible_v<U(*)[], element_type(*)[]>` が `true` であること。(この制約の意図は、イテレータ参照型から `element_type` への修飾変換のみを許可すること)
- (9) :
  - `extent == dynamic_extent || OtherExtent == dynamic_extent || extent == OtherExtent`が`true`であること (受け取り側が`dynamic_extent`を持っていれば任意の`Extent`から変換できる)
  - `OtherElementType(*)[]`型が`ElementType(*)[]`型に変換可能であること

## 堅牢化された事前条件

- (2) :
  - `[first, first + count)`が妥当なイテレータ範囲であること
  - 型 `It` はコンセプト `std::contiguous_iterator` のモデルであること
  - メンバ定数`extent`が`dynamic_extent`と等値ではない場合、`count`と`extent`が等値であること
- (3) :
  - `[first, last)`が妥当なイテレータ範囲であること
  - メンバ定数`extent`が`dynamic_extent`と等値ではない場合、`last - first`と`extent`が等値であること
  - 型 `It` はコンセプト `std::contiguous_iterator` のモデルであること
  - 型 `End` はコンセプト `std::sized_sentinel_for<It>` のモデルであること
- (7) :
  - `extent`が`dynamic_extent`と等値でない場合、`extent`は`ranges::size(r)`と等値になる
  - 型 `R` はコンセプト `std::ranges::contiguous_range` 及び `std::ranges::sized_range` のモデルであること
  - `std::is_const_v<element_type>` が `false`であるとき、型 `R` はコンセプト `std::ranges::borrowed_range` のモデルであること
- (9) :
  - `extent`が`dynamic_extent`と等値でない場合、`extent`は`s.size()`と等値になる

## 効果

- (2) : イテレータ範囲`[first, first + count)`を参照する`span`オブジェクトを構築する
- (3) : イテレータ範囲`[first, last)`を参照する`span`オブジェクトを構築する
- (4), (5), (6) : 範囲`[data(arr), data(arr) + N)`を参照する`span`オブジェクトを構築する
- (7) : 範囲`[std::ranges::data(r), std::ranges::data(r) + std::ranges::size(r))`を参照する`span`オブジェクトを構築する
- (9) : 範囲`[s.data(), s.data() + s.size())`を参照する`span`オブジェクトを構築する

## 事後条件

- (1) : `size() == 0 && data() == nullptr`が`true`であること
- (4), (5), (6) : `size() == N && data() == data(arr)`が`true`であること
- (8) : `size() == size(cont) && data() == data(cont)`が`true`であること
- (9) : `size() == s.size() && data() == s.data()`が`true`であること

## 例外

- (1), (2), (4), (5), (6) : 投げない
- (3) : `last - first`がなんらかの例外を送出する可能性がある
- (7) : コンテナ型によっては、`std::ranges::data(r)`と`std::ranges::size(r)`の呼び出しがなんらかの例外を送出する可能性がある

## 計算量

- (1)-(9) : 定数時間

## 例

### 基本的な使い方 (C++20)

    #include <cassert>
    #include <span>
    #include <vector>
    #include <array>
    #include <string>

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

      // (1) デフォルトコンストラクタ
      {
        // 長さ0の参照範囲をもつspanオブジェクト
        std::span<int, 0> s1;
        assert(s1.empty());

        // 動的な要素数をもつspanオブジェクト
        std::span<int> s2;
        assert(s2.empty());

        // 以下はコンパイルエラーになる。
        // 長さ1以上のspanは、参照範囲を設定しなければならない
        // std::span<int, 1> s3{};
      }

      // (2) イテレータと要素数の組を指定
      {
        // vの先頭3要素を参照する。
        std::span<int> s{v.begin(), 3};
        assert(s.size() == 3);
        assert(s[0] == 1);
        assert(s[1] == 2);
        assert(s[2] == 3);
      }

      // (3) 範囲を指定
      {
        std::span<int> s{v.begin(), v.begin() + 3};
        assert(s.size() == 3);
        assert(s[0] == 1);
        assert(s[1] == 2);
        assert(s[2] == 3);
      }

      // (4) 組み込み配列への参照を指定
      {
        int ar[] = {1, 2, 3, 4, 5};
        std::span<int> s{ar};
        assert(s.size() == 5);
        assert(s.data() == ar); // 元の配列をコピーせず、参照している
      }

      // (5) std::arrayオブジェクトへの参照を指定
      {
        std::array ar = {1, 2, 3, 4, 5};
        std::span<int> s{ar};
        assert(s.size() == ar.size());
        assert(s.data() == ar.data());
      }

      // (6) const std::arrayオブジェクトへの参照を指定
      {
        std::array ar = {1, 2, 3, 4, 5};
        const auto& car = ar;
        std::span<const int> s{car};

        assert(s.size() == car.size());
        assert(s.data() == car.data());
      }

      // (7) メモリの連続性をもつイテレータをもつオブジェクトの要素全体を参照させる
      {
        std::span<int> s1{v};
        assert(s1.size() == v.size());
        assert(s1.data() == v.data());

        // std::string_viewの代わり
        std::string str = "Hello";
        std::span<char> s2{str};
        assert(s2.size() == str.size());
        assert(s2.data() == str.data());
      }

      // (8) コピーコンストラクタ
      {
        std::span<int> s1{v};
        std::span<int> s2 = s1;

        // コピー元とコピー先が同じ範囲を参照する
        assert(s1.data() == v.data());
        assert(s2.data() == v.data());
      }

      // (9) 変換コンストラクタ
      {
        int ar[] = {1, 2, 3};

        std::span<int, 3> s1{ar};
        std::span<int> s2 = s1;
        std::span<int> s3 = s2.first(2);
        std::span<const int> s4 = s3;

        assert(s4.size() == 2);
        assert(s4.data() == ar);
      }
    }

#### 出力

## バージョン

### 言語

- C++20

### 処理系

- Clang: (10.0.0 現在、実装は P1394R4 以前の不完全なものである) ✅
- GCC: 10.0.1 ✅
- Visual C++: ??

## 参照

- LWG Issue 3100. Unnecessary and confusing "empty span" wording
- LWG Issue 3101. `span`'s Container constructors need another constraint
- LWG Issue 3198. Bad constraint on `std::span::span()`
- P1872R0 `span` should have `size_type`, not `index_type`
- P1394R4 Range constructor for `std::span`
- P1976R2 Fixed-size `span` construction from dynamic range
- P2117R0 C++ Standard Library Issues Resolved Directly In Prague
- P2447R6 `std::span` over an initializer list
  - P4144R1 Remove `span`’s `initializer_list` constructor for C++26
  - C++26の策定中に一時期、初期化子リストをとるコンストラクタが追加されたが、その後削除された
- P3471R4 Standard library hardening
- P3878R1 Standard library hardening should not use the 'observe' semantic