最終更新日時: 2025年07月09日 00時33分39秒 (JST)
Akira Takahashi が更新

履歴 編集

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, 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 ✅

## 関連項目

- C++20 コンセプト

## 参照

- P0896R4 The One Ranges Proposal (was Merging the Ranges TS)