最終更新日時(UTC):
が更新

履歴 編集

concept
<iterator>

std::sized_sentinel_for(C++20)

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, Ssized_sentinel_forのモデルである。

  • Niter_difference_t<I>で表現可能な場合、s - iは適格でありNと等値となる
  • -Niter_difference_t<I>で表現可能な場合、i - sは適格であり-Nと等値となる

備考

イテレータ型I, Sが本コンセプトを構文的には満たしているが意味論的な制約まで満たすことができない(モデルとならない)場合に、sized_sentinel_for<S, I> == falseとするためにはdisable_sized_sentinel_fortrueとなるように特殊化する。

#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

処理系

関連項目

参照