namespace std::ranges {
template<class T>
concept range = requires(T& t) {
ranges::begin(t);
ranges::end(t);
};
}
概要
要素の範囲を表すイテレータと番兵を取得でき、それらによって要素をイテレートできる型を表す、Rangeの最も基本的なコンセプト。
モデル
decltype((t))がT&であるような式tがあるとする。Tがrangeのモデルとなるのは、以下の条件をすべて満たす場合である。
- [
ranges::begin(t),ranges::end(t)) が範囲を表す。 ranges::begin(t)とranges::end(t)は共に償却定数時間で値を返し、Rangeを変更しない。ranges::begin(t)の型がforward_iteratorのモデルであるならば、ranges::begin(t)は等しさを保持する。
式が等しさを保持する(equality‑preserving)とは、同じ入力に対しては常に同じ結果となることをいう。
イテレータiに前置インクリメントを有限回適用したとき、番兵sと等しくなるならば、sはiから到達可能であるという。また、そのとき、[i, s)は範囲を表す。
1番目の要件では、同じRangeオブジェクトから取得したイテレータと番兵は、同じRangeのイテレータと番兵であることが要求される。特に、有限長のRangeであれば、番兵はイテレータから到達可能でなければならない。 2番目の要件では、要件が償却定数時間であることにより、イテレータを取得するタイミングで初めて要素を生成するような実装が許可される。
備考
forward_iteratorなRangeに対してranges::beginとranges::endの両方が等しさを保持するならば、そのRangeを何度もアルゴリズム関数に渡したり、イテレータを繰り返し取得して使ったりしてもよい。
イテレータがforward_iteratorのモデルではない場合は、ranges::beginでイテレータを繰り返し取得したときに同じオブジェクトが返る保証はなく、結果が一意に定まるともいえない。そのような場合、ranges::beginの呼び出しはRange1つあたり1回に留めなければならない。
例
#include <ranges>
#include <vector>
int main()
{
static_assert(std::ranges::range<std::vector<int>>);
static_assert(std::ranges::range<int[3]>);
static_assert(!std::ranges::range<double>);
static_assert(!std::ranges::range<const char*>);
static_assert(!std::ranges::range<int[]>);
}
出力
バージョン
言語
- C++20
処理系
- Clang: 13.0.0 ✅
- GCC: 10.1.0 ✅
- ICC: ??
- Visual C++: 2019 Update 10 ✅