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) : 定数時間
例
#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 havesize_type
, notindex_type
- P1394R4 Range constructor for
std::span
- P1976R2 Fixed-size
span
construction from dynamic range - P2117R0 C++ Standard Library Issues Resolved Directly In Prague