- iterator[meta header]
- std[meta namespace]
- concept[meta id-type]
- cpp20[meta cpp]
namespace std {
// C++20
template<class S, class I>
concept sentinel_for =
semiregular<S> &&
input_or_output_iterator<I> &&
weakly-equality-comparable-with<S, I>;
// C++26
template<class S, class I>
concept sentinel_for =
semiregular<S> &&
!is-integer-like<S> &&
input_or_output_iterator<I> &&
weakly-equality-comparable-with<S, I>;
}- semiregular[link /reference/concepts/semiregular.md]
- is-integer-like[link /reference/iterator/is_integer_like.md]
- input_or_output_iterator[link /reference/iterator/input_or_output_iterator.md]
- weakly-equality-comparable-with[link /reference/concepts/equality_comparable.md]
sentinel_forは、任意のsemiregularな型Sがイテレータ型Iの番兵(sentinel)型である事を表すコンセプトである。
番兵型とは、イテレータ範囲[begin, end)においてのendを表す型の事である。これは通常beginの型と同じになるが、等値比較可能でありさえすれば別の型であっても構わない。
型I, Sの値i, sとそれによって示される範囲[i, s)について次の条件を満たす場合に限って、型I, Sはsentinel_forのモデルである。
i == sが適格である(未定義動作にならない)bool(i != s) == trueの(iが範囲終端に到達していない)時、iは間接参照可能であり[++i, s)も範囲を示すI&, Sがassignable_from<I&, S>のモデルとならないなら、構文的にもassignable_fromコンセプトを満たさない- (C++26)
IとSが同じ型である場合、i == iはtrueである
ここでの==の定義域は静的ではなく、実行時に変化しうる。[i, s)が範囲を示している時にi == oiとなるような別のイテレータoiをインクリメント(++oi)した後で、範囲[i, s)が有効であり続ける必要はない。
#include <iostream>
#include <iterator>
#include <vector>
template<typename I, std::sentinel_for<I> S>
void f(const char* namei, const char* names) {
std::cout << names << " is sentinel for " << namei << std::endl;
}
template<typename I, typename S>
void f(const char* namei, const char* names) {
std::cout << names << " is not sentinel for " << namei << std::endl;
}
struct sample_sentinel{};
struct sample_input_or_output_iterator {
friend auto operator++(sample_input_or_output_iterator&) -> sample_input_or_output_iterator&;
friend auto operator++(sample_input_or_output_iterator&, int) -> sample_input_or_output_iterator;
friend auto operator*(sample_input_or_output_iterator&) -> int;
friend bool operator==(const sample_input_or_output_iterator&, sample_sentinel);
using difference_type = int;
};
int main() {
f<int*, int*>("int*", "int*");
f<const int*, int*>("const int*", "int*");
f<int*, const int*>("int*", "int* const");
f<std::vector<int>::iterator, std::vector<int>::iterator>("std::vector<int>::iterator", "std::vector<int>::iterator");
f<sample_input_or_output_iterator, sample_sentinel>("sample_input_or_output_iterator", "sample_sentinel");
std::cout << "\n";
f<std::vector<int>::iterator, int*>("std::vector<int>::iterator", "int*");
f<double*, int*>("double*", "int*");
}- std::sentinel_for[color ff0000]
int* is sentinel for int*
int* is sentinel for const int*
int* const is sentinel for int*
std::vector<int>::iterator is sentinel for std::vector<int>::iterator
sample_sentinel is sentinel for sample_input_or_output_iterator
int* is not sentinel for std::vector<int>::iterator
int* is not sentinel for double*
- C++20
- Clang: ??
- GCC: 10.1 [mark verified]
- Visual C++: 2019 Update 6 [mark verified]
- P0896R4 The One Ranges Proposal (was Merging the Ranges TS)
- LWG Issue 3453. Generic code cannot call
ranges::advance(i, s) - LWG Issue 3777. Common
cartesian_product_viewproduces invalid range if first range is input and one range is empty- C++26で、
IとSが同じ型のときi == iがtrueであるという意味論要件がモデルに追加された
- C++26で、
- LWG Issue 4510. Ambiguity of
std::ranges::advanceandstd::ranges::nextwhen the difference type is also a sentinel type- C++26で、番兵型
Sが整数類似型でないこと(!is-integer-like<S>)が制約に追加された。差分型が番兵型のモデルにもなる場合に、ranges::advance/ranges::nextのオーバーロードが曖昧になる問題を回避するもの
- C++26で、番兵型