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
spanshould havesize_type, notindex_type - P1394R4 Range constructor for
std::span - P1976R2 Fixed-size
spanconstruction from dynamic range - P2117R0 C++ Standard Library Issues Resolved Directly In Prague
- P2447R6
std::spanover an initializer list- P4144R1 Remove
span’sinitializer_listconstructor for C++26 - C++26の策定中に一時期、初期化子リストをとるコンストラクタが追加されたが、その後削除された
- P4144R1 Remove
- P3471R4 Standard library hardening
- P3878R1 Standard library hardening should not use the 'observe' semantic