[C++]イテレータパターンを範囲for文で回す。


# 前提

## イテレーターパターン

デザインパターンの一種。

細かい亜種が有るようだが、
今回は、以下のインターフェースを持つ物を対象とする。
```cpp
template<class T>
struct Iterator{
  virtual void Next() = 0 ;
  virtual T    Item() = 0 ;
  virtual bool HasNext() = 0 ;
};
```

これは通常、
```cpp
std::unique_ptr<Iterator<T>> Sequence() ; // Iteratorパターンを返す関数

for ( auto it = Sequence() ; it->HasNext() ; it->Next() ){
  T item = it->Item() ;
  ...
}
```
の様に走査をする。

## やりたい事

上記のイテレータパターンの物を、範囲for文を使って
```cpp
for ( const auto& item : it ) {
  ...
}
```
と走査したい。

# 結論

以下の実装を加えれば良い。

```cpp
namespace impl {
template<class T>
struct Iterator_ {
  T operator*() const { return it->Item() ; }
  bool operator!=( const Iterator_& ) const { return it && it->HasNext(); }
  void operator++() const { it->Next(); }
  Iterator<T>* it ;
};
} // impl

template<class T>
impl::Iterator_<T> begin( const std::unique_ptr<Iterator<T>>& it ) { return{ it.get()}; }
template<class T>
impl::Iterator_<T> end  ( const std::unique_ptr<Iterator<T>>& it ) { return{ nullptr };/*dummy*/ }
```

コード全体は[こちら](https://gitlab.com/kmr.yuichi/cpp-iterater-rangebased-for-sample/-/blob/main/main.cpp)。



# 解説

上記コードに如何様に至ったかの話。[Gitのコミットログ](https://gitlab.com/kmr.yuichi/cpp-iterater-rangebased-for-sample/-/commits/main)も参照。


## 1. 範囲for文の展開

見通しを良くするため、冗長な書き方に展開する。
* 範囲for文は糖衣構文。( i.e. 冗長な記述を簡潔に書くための構文,シンタックスシュガーとも)
* 今回は、[範囲for文の仕様](https://cpprefjp.github.io/lang/cpp11/range_based_for.html)の、"範囲の型が配列でもメンバbegin、endのいずれかを持つクラスでもないとき" に該当する。

```cpp
auto&& range_ = Sequence( 10 ) ;
for ( auto begin_ = begin( range_ ), end_ = end( range_ ); begin_ != end_; ++begin_ ) {
  const auto& item = *begin_;

  ...
}
```
## 2. begin,end の用意

ビルドするとフリー関数の `begin`, `end` が必要なことが分かるので、これを用意する。

* C++14 までは、`begin`, `end` の戻り地の型は一致する必要がある。

```cpp
struct Iterator_ {
};

Iterator_ begin( const std::unique_ptr<Iterator<int>>& it ) {}
Iterator_ end  ( const std::unique_ptr<Iterator<int>>& it ) {}
```

## 3. イテレータの実装

戻り値の型 `Iterator_` に対して、`*`,`!=`,`++` が行える必要があるので、
メンバ関数としてこれを用意する。


```cpp
struct Iterator_ {
  int  operator* ()                     const {}
  bool operator!=( const Iterator_& r ) const {}
  void operator++()                     const {}
};
```

通常の走査と展開後を比べて見ると、

```cpp:通常の走査
for
(
  auto it = Sequence( 10 ) ; // 初期化
  it->HasNext() ;            // インクリメント
  it->Next()                 // 終了条件
) {
  const auto item = it->Item() ; // 各要素の変数の定義
  ...
}
```
```cpp:展開後
for
(
  auto begin_ = begin( range_ ), end_ = end( range_ ); // 初期化
  begin_ != end_ ;                                     // インクリメント
  ++begin_                                             // 終了条件
) {
  const auto& item = *begin_; // 各要素の変数の定義
  ...
}
```

各関数は、おおよそ、以下の様な実装をすれば良いと分かる。
```cpp
struct Iterator_ {
  int  operator* ()                     const { return it->Item()   ; }
  bool operator!=( const Iterator_& r ) const { return it->HasNext(); }
  void operator++()                     const { it->Next()          ; }
};
```

## 3. ビルドを通す

ビルドを通すため、必要な情報を受け渡す。

```cpp
struct Iterator_ {
  ...
  const std::unique_ptr<Iterator<int>>& it ;
};
Iterator_ begin( const std::unique_ptr<Iterator<int>>& it ) { return Iterator_{ it }; }
```

`end` で返す値は`!=`の右辺でしか使われ無いため、適当な何かを返せば良い。

```cpp
Iterator_ end( const std::unique_ptr<Iterator<int>>& it ) { return Iterator_{ it };/*dummy*/ }
```

## 4. 微調整
テンプレート化,nullチェックの対応などをして、完成。

# note

C++17以降は、`begin` と `end` の戻り値の型が異なっていても構わない。
* 今回なら、`end`は `nullptr_t` を返すのが良さそう。
  * 組み込み型のため余分な定義などが要らず、単一の値しか取らないため無為な値を示すのに適する。