Project Euler 7(2)

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;
}