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 ✅