C++でPythonのrange(n)をなるべく簡潔に実現

# 注意
WandBoxのclangではうまく動かないようです（コメント参照）

# 目標
Pythonの`for i in range(n)`と同等のものをC++の範囲ベース`for`を用いて`for(auto i:range(n))`と書けるようにします．つまり，次のforループと同じ動作をするものです．
```C++
for(int i = 0; i < n ; ++i)
```

# 方針
あらかじめ0,1,...,n-1が格納された配列等を用意しておけば，比較的簡単に実現できるのですが，この方法では$O(n)$のメモリと実行時間が必要となります．たとえforループが早期に中断された場合でも，これらのコストが発生します。そこで，必要に応じてlazyに生成する方法を，なるべく簡潔に実現します．

# イテレータを作る
例えば，下の範囲ベースのforを実行すると，0からn-1が表示されるようにします．
```C++
  for(const auto i: range(n))
    std::cout << i << "\n";
```
同様の動作をするイテレータベースの`for`は次のように書くことができます．
```C++
  for (auto it = range(n).begin(); it != range(n).end(); ++it)
    std::cout << *it << "\n";
```
大雑把に言えば，この`for`が正しく動作するように，`range`クラスを設計すれば，範囲ベースの`for`も機能します．そのためには，以下のメンバ関数や演算子のオーバーロードを設定します．
* `begin()`：最初の要素を指すイテレータ
* `end()`：最後の要素を指すイテレータ
* `&operator*()`: ポインタ演算子`*`で，イテレータが指す先の値を返す
* `operator!=`: 不等価演算子`!=`で，イテレータが一致するかどうかを返す
* `&operator++`: インクリメント演算子`++`で，次の要素を指すようにイテレータを更新する
通常，`begin()`等は，イテレータを返すべきなのですが，あえて無視して，イテレータベースの`for`が動くようにすればいいという方針で，簡潔に設計します．

# ソースコード
`range`クラスを定義します．
* メンバ変数`n`：ここに格納する値で，値自身とイテレータの両方を表します．
* コンストラクタ`range(int n)`：引数`n`でメンバ変数`n`を初期化します．
* `auto begin()`：`range(0)`を返すので，`it = range(n).begin()`の場合，`n`の値に依存せず，`it`に`range(0)`が代入されます．
* `auto end()`：インスタンス自身を返すので，`range(n).end()`は`range(n)`を返します．
* `int &operator*()`：メンバ変数`n`の値を返します．よって，`*it`は，`it`が持つ`range`のインスタンスのメンバ変数`n`の値となります．
* `bool operator!=`：2つの`range`のインスタンスが一致するかどうか判定します．よって，`it != range(n).end()`は`it`が`range(n)`ではない場合に，`true`となります．
* `range &operator++()`：`range`のインスタンスの`n`の値を1増やし，インスタンス自身を返します．したがって，`++it`では，`range`のインスタンス`it`がもつ`n`の値が1増えます．

```C++
class range {
  int n;

public:
  range(int n) : n(n) {}
  auto begin() { return range(0); }
  auto end() { return *this; }
  int &operator*() { return n; }
  bool operator!=(const range &r) { return n != r.n; }
  range &operator++() {
    ++n;
    return *this;
  }
};
```
イテレータベースの`for`を使って，0から9までを表示するプログラムは次のようになります．
```C++
int main() {
  for (auto it = range(10).begin(); it != range(10).end(); ++it)
    std::cout << *it << "\n";
}
```
範囲ベースの`for`では次のように簡潔に書くことができます．
```C++
int main() {
  for(const auto i:range(10))
    std::cout << i << "\n";
}
```
実行結果は次のようになり，意図した通り動作しています．
```
0
1
2
3
4
5
6
7
8
9
```

# ChatGPT-4に聞いてみた
ちなみに，ChatGPT-4にこのコードの添削を求めると，次のようにダメ出しされました．

**ChatGPT**: 提供されたコードにはいくつかの誤解や誤りが含まれています。これらを修正して、意図された挙動を正しく達成するためには次のような変更が必要です。

**誤りとその修正**
1. **begin() と end() メソッドの誤使用**:
 現在の**begin()** が **range(0)** を返していますが、これは単に **n = 0** の新しい **range** オブジェクトを作成します。これでは、イテレータとして機能しません。 **end()** も同様に **range(n)** を返していますが、これはイテレータではなく、範囲の終わりを示す値としてのみ意味を持ちます。
2. **range クラスがイテレータの責務も担っている**:
クラス **range** がコンテナの役割とイテレータの役割の両方を担っています。これは設計として混乱を招く可能性があります。イテレータは別のクラスとして定義するべきです。
以下に、上記の問題を解決し、範囲ベースの **for** ループで利用できるように修正したコードを示します。

```C++
#include <iostream>

class range {
public:
    class iterator {
        int pos;
    public:
        iterator(int pos) : pos(pos) {}
        bool operator!=(const iterator& other) const { return pos != other.pos; }
        int operator*() const { return pos; }
        iterator& operator++() { ++pos; return *this; }
    };

    range(int n) : begin_(0), end_(n) {}
    iterator begin() const { return iterator(begin_); }
    iterator end() const { return iterator(end_); }

private:
    int begin_, end_;
};

int main() {
    for (auto i : range(10)) {
        std::cout << i << "\n";
    }
    return 0;
}
```
このコードでは、**range** クラス内に **iterator** サブクラスが定義されています。**begin()** と **end()** メソッドは、それぞれ開始位置と終了位置を示す **iterator** インスタンスを返します。この設計により、範囲ベースの **for** ループを自然に使うことができ、**Python** の **for i in range(n)** に近い形での使用が可能になります。

# おわりに
ChatGPTはメンバ変数を3つ使っていますが，ここで紹介したイテレータを無視する実装方法では，使用するメンバ変数は1つだけです．
また，`C++20`であれば`std::views::iota`を使って簡単に書けるようです．