namespace std {
template<class S, class I>
concept sized_sentinel_for =
sentinel_for<S, I> &&
!disable_sized_sentinel_for<remove_cv_t<S>, remove_cv_t<I>> &&
requires(const I& i, const S& s) {
{ s - i } -> same_as<iter_difference_t<I>>;
{ i - s } -> same_as<iter_difference_t<I>>;
};
}
概要
sized_sentinel_forは、任意のイテレータ型Iとその番兵型Sの間でoperator-によって定数時間で距離が求められる事を表すコンセプトである。
モデル
型I, Sの値i, sとそれによって示される範囲[i, s)、bool(i == s) == trueとなるために必要な++iの最小の適用回数をNとする。それらi, s, Nについて次の条件を満たす場合に限って、型I, Sはsized_sentinel_forのモデルである。
Nがiter_difference_t<I>で表現可能な場合、s - iは適格でありNと等値となる-Nがiter_difference_t<I>で表現可能な場合、i - sは適格であり-Nと等値となる
備考
イテレータ型I, Sが本コンセプトを構文的には満たしているが意味論的な制約まで満たすことができない(モデルとならない)場合に、sized_sentinel_for<S, I> == falseとするためにはdisable_sized_sentinel_forをtrueとなるように特殊化する。
例
#include <iostream>
#include <iterator>
#include <vector>
template<typename I, std::sized_sentinel_for<I> S>
void f(const char* namei, const char* names) {
std::cout << names << " is sized sentinel for " << namei << std::endl;
}
template<typename I, typename S>
void f(const char* namei, const char* names) {
std::cout << names << " is not sized sentinel for " << namei << std::endl;
}
struct sample_sentinel{};
struct sample_sized_iterator {
friend auto operator++(sample_sized_iterator&) -> sample_sized_iterator&;
friend auto operator++(sample_sized_iterator&, int) -> sample_sized_iterator;
friend auto operator*(sample_sized_iterator&) -> int;
friend bool operator==(const sample_sized_iterator&, sample_sentinel);
// input_or_output_iteratorに加えて、この2つを定義すればsized_sentinel_forとなる
friend auto operator-(const sample_sized_iterator&, sample_sentinel) -> int;
friend auto operator-(sample_sentinel, const sample_sized_iterator&) -> int;
// std::default_sentinel_tは使用可能にしておく
friend bool operator==(const sample_sized_iterator&, std::default_sentinel_t);
friend auto operator-(const sample_sized_iterator&, std::default_sentinel_t) -> int;
friend auto operator-(std::default_sentinel_t, const sample_sized_iterator&) -> int;
using difference_type = int;
};
// disable_sized_sentinel_forをtrueで特殊化することでsized_sentinel_forを不適合にする
template<>
inline constexpr bool std::disable_sized_sentinel_for<sample_sentinel, sample_sized_iterator> = true;
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_sized_iterator, std::default_sentinel_t>("sample_sized_iterator", "std::default_sentinel");
std::cout << "\n";
f<std::vector<int>::iterator, int*>("std::vector<int>::iterator", "int*");
f<double*, int*>("double*", "int*");
f<sample_sized_iterator, sample_sentinel>("sample_sized_iterator", "sample_sentinel");
}
出力
int* is sized sentinel for int*
int* is sized sentinel for const int*
int* const is sized sentinel for int*
std::vector<int>::iterator is sized sentinel for std::vector<int>::iterator
std::default_sentinel is sized sentinel for sample_sized_iterator
int* is not sized sentinel for std::vector<int>::iterator
int* is not sized sentinel for double*
sample_sentinel is not sized sentinel for sample_sized_iterator
バージョン
言語
- C++20
処理系
- Clang: ??
- GCC: 10.1 ✅
- Visual C++: 2019 Update 6 ✅