Pythonでisum,ifilter,irangeを自作して、
def isum(a): s = 0 for e in a: s += e return s def ifilter(f, a): for e in a: if f(e): yield e def irange(begin, end): n = begin while n < end: yield n n += 1 print isum(ifilter(lambda n: n % 3 == 0 or n % 5 == 0, irange(1, 1000)))
このようにC++でも書きたい。
ジェネレータは関数オブジェクトで実現する。まずは、range。
template<typename T = int> class range { T current; T end; T delta; public: range(T b, T e, T d = 1) : current(b), end(e), delta(d) { } range(T e) : end(e) { current = 0; delta = d; } range() { current = end = delta = 0; } T next() { if(current < end) { T v = current; current += 1; return v; } else { throw(1); } } };
Pythonと同様に、next()で値を出す。最後まで来たら、これもPython同様例外を投げる。Python同様intだけでいいとも思ったが、一応テンプレートを使っておく。
次にsum。
template<typename T> auto sum(T& o) -> decltype(o.next()) { auto s = 0; try { while(true) { s += o.next(); } } catch(int e) { return s; } }
返り値の型を指定は、上のようにdecltypeを使うと回避できるらしい。
filterはrangeと同様に作って、結局このようになった。
#include <iostream> using namespace std; const int N = 1000; // sumとrangeは省略 template<typename T, typename U, typename V> class filter { T pred; U obj; public: filter(T p, U o) : pred(p), obj(o) { } V next() { decltype(obj.next()) v; do { v = obj.next(); } while(!pred(v)); return v; } }; int main() { struct f { bool operator ()(int n) const { return n % 3 == 0 || n % 5 == 0; } }; cout << sum(filter<struct f,range<>,int>( f(), range<>(1, N))) << endl; }
うーむ。