Project Euler 1(4)

テンプレート引数がいちいちついて回るのは、クラスを関数で包めば回避できる。例えばmapなら、

template<typename T, typename U, typename V>
class cMap {
    T&  func;
    U&  gen;
    
public:
    cMap(T& f, U& g) : func(f), gen(g) { }
    V next() {
        return func(gen.next());
    }
};

template<typename T, typename U>
auto map(T& func, U& gen) -> cMap<T,U,decltype(func(gen.next()))>{
    return cMap<T,U,decltype(func(gen.next()))>(func, gen);
}

これを次のように使う。

cout << sum(map([] (int n) { return n * 2; }, range<>(10))) << endl;

ラムダも使える。
最初、gen.next()の返り値の型Vをクラスのほうでひねり出そうとしたができなくて、これも関数に押し付けたらあっさり通った。

#include <iostream>

using namespace std;

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) : current(0), end(e), delta(1) { }
    range() : current(0), end(0), delta(0) { }
    
    T next() {
        if(current < end) {
            T   v = current;
            current += delta;
            return v;
        }
        else {
            throw(1);
        }
    }
};

template<typename T, typename U, typename V>
class cFilter {
    T&  pred;
    U&  gen;
    
public:
    cFilter(T& p, U& g) : pred(p), gen(g) { }
    V next() {
        V   v;
        do
            v = gen.next();
        while(!pred(v));
        return v;
    }
};

template<typename T, typename U>
auto filter(T& pred, U& gen) -> cFilter<T,U,decltype(gen.next())>{
    return cFilter<T,U,decltype(gen.next())>(pred, gen);
}

template<typename T>
auto sum(T& gen) -> decltype(gen.next()) {
    decltype(gen.next())    s = 0;
    try {
        while(true)
            s += gen.next();
    }
    catch(int e) {
        return s;
    }
}

int main() {
    const int   N = 1000;
    
    cout << sum(filter([] (int n) { return n % 3 == 0 || n % 5 == 0; },
                                                range<>(1, N))) << endl;
}