takewhileなどのジェネレータは関数を引数に持つ。しかし、型指定をしたくないのでラムダは使えず、関数の型も限られたものになる。引数が一つであればいいが、他に環境からもってくることができない。
そこで、関数は2つの引数を取るものも使えるようにし、それは2つ目の引数をvoid *で受けるものとする。こんな感じの関数。
bool le_sq(int p, void *env) { int n = *(int *)env; return p * p <= n; }
takewhileももう一つ引数を取る。
bool is_prime(int n) { return all([n](int p) { return n % p != 0; }, new takewhile<int>(le_sq, (void *)&n, new genPrimes())); }
#include <cmath> #include "itertools.h" using namespace std; using namespace itertools; const int N = 10001; vector<int> primes(1, 2); bool is_prime(int n); class genPrimes : public cGenerator<int> { int k; public: genPrimes() : k(0) { } int next() { int p; // 他でprimesが成長しているかもしれないので // 毎回サイズをチェックする // マルチスレッドでは使えない if(k < (int)primes.size()) { p = primes[k]; } else { p = head(new filter<int>( is_prime, new count<>(primes[k-1] + 1))); primes.push_back(p); } k++; return p; } genPrimes *copy() const { return new genPrimes(); } }; bool le_sq(int p, void *env) { int n = *(int *)env; return p * p <= n; } bool is_prime(int n) { return all([n](int p) { return n % p != 0; }, new takewhile<int>(le_sq, (void *)&n, new genPrimes())); } bool is_reached(tuple<int,int> x) { return get<0>(x) == N; } int main() { auto t = head(new filter<tuple<int,int>>(is_reached, new zip<int,int>(new count<int>(1), new genPrimes()))); cout << get<1>(t) << endl; }