range

Pythonのitertoolsを使ったような書き方がC++でもできるようにライブラリを作っていきます。具体的には、例えば、1から10の和を求めるときにこう書けるようにします。

    cout << sum(range(1, 11)) << endl;

Pythonのxrangeやtakewhileをクラスを使って実現します。これらは、cIterableを継承します。Tは発生する値の型です。

template<typename T>
class cIterable {
public:
    virtual ~cIterable() { }
    virtual bool exists_next() = 0;
    virtual T value() const = 0;
};

そして、これを関数で包んで型推論させてポインタを返します。再帰で使うときにポインタだと書きやすいからです(たぶん)。しかしメモリの管理はしたくないので、shared_ptrを使います。したがって、関数はshared_ptr>を返すことになります。

まず、Pythonのxrangeをrangeという関数名で実現しました。

#include <iostream>
#include <memory>

using namespace std;

template<typename T>
class cIterable {
public:
    virtual ~cIterable() { }
    virtual bool exists_next() = 0;
    virtual T value() const = 0;
};

class cRange : public cIterable<int> {
    int     current;
    int     end;
    int     delta;
    bool    first;
    
public:
    cRange(int e) : current(0), end(e), delta(1), first(true) { }
    cRange(int b, int e) : current(b), end(e), delta(1), first(true) { }
    cRange(int b, int e, int d) : current(b), end(e), delta(d), first(true) { }
    
    ~cRange() { cout << "cRange::~cRange" << endl; }
    bool exists_next() {
        if(first)
            first = false;
        else
            current += delta;
        return delta > 0 ? current < end : current > end;
    }
    int value() const {
        return current;
    }
};

shared_ptr<cIterable<int>> range(int e) {
    return shared_ptr<cIterable<int>>(new cRange(e));
}

shared_ptr<cIterable<int>> range(int b, int e) {
    return shared_ptr<cIterable<int>>(new cRange(b, e));
}

shared_ptr<cIterable<int>> range(int b, int e, int d) {
    return shared_ptr<cIterable<int>>(new cRange(b, e, d));
}

template<typename T>
ostream operator <<(ostream& os, const shared_ptr<cIterable<T>>& g) {
    if(g->exists_next()) {
        os << g->value();
        while(g->exists_next())
            os << " " << g->value();
    }
    return os;
}

int main() {
    auto    r = range(1, 11);
    cout << r << endl;
}