Pythonではジェネレータでこういうことができます。
def gen(): for n in range(3): for m in range(n + 1, 4): yield (n, m)
(0, 1) (0, 2) (0, 3) (1, 2) (1, 3) (2, 3)
直積ではなく、mを出すiterableがnに依存しています。これを実現するにはどうすればよいでしょう。
それには、nに応じてmのiterableを返すような関数オブジェクトを引数にすればよいでしょう。こんな感じです。
auto g = product(range(3), [](int n) { return range(n + 1, 4); });
前回の直積と同じ関数名にしています。以前同じようなことをやったときは、SFINAEで関数オブジェクトかどうか判別していましたが、今回はshared_ptrを使っているので単なるオーバーロードになっています。
template<typename T, typename U> class cProduct : public cIterable<tuple<T,U>> { shared_ptr<cIterable<T>> gen1; shared_ptr<cIterable<U>> gen2; vector<U> v; typename vector<U>::const_iterator p; int mode; public: cProduct(shared_ptr<cIterable<T>> g1, shared_ptr<cIterable<U>> g2) : gen1(g1), gen2(g2), mode(0) { } bool exists_next() { if(mode == 0) { if(!gen1->exists_next()) return false; else if(!gen2->exists_next()) return false; mode = 1; v.push_back(gen2->value()); return true; } else if(mode == 1) { if(gen2->exists_next()) { v.push_back(gen2->value()); return true; } else if(gen1->exists_next()) { p = v.begin(); mode = 2; return true; } else { return false; } } else { ++p; if(p != v.end()) { return true; } else if(gen1->exists_next()) { p = v.begin(); return true; } else { return false; } } } tuple<T,U> value() const { T y = mode == 1 ? gen2->value() : *p; return tuple<T,U>(gen1->value(), y); } }; template<typename T, typename U> shared_ptr<cIterable<tuple<T,U>>> product(shared_ptr<cIterable<T>> g1, shared_ptr<cIterable<U>> g2) { return shared_ptr<cIterable<tuple<T,U>>>(new cProduct<T,U>(g1, g2)); } template<typename T, typename U, typename V> class cDependentlyProduct : public cIterable<tuple<T,U>> { shared_ptr<cIterable<T>> gen1; shared_ptr<cIterable<T>> gen2; V func; bool first; public: cDependentlyProduct(shared_ptr<cIterable<T>> g, V f) : gen1(g), func(f), first(true) { } bool exists_next() { if(first) { first = false; return next1(); } else if(!gen2->exists_next()) return next1(); else return true; } tuple<T,U> value() const { return tuple<T,U>(gen1->value(), gen2->value()); } private: bool next1() { if(!gen1->exists_next()) return false; gen2 = func(gen1->value()); return gen2->exists_next(); } }; template<typename T, typename V> auto product(shared_ptr<cIterable<T>> g, V f) -> shared_ptr<cIterable<tuple<T,decltype(f(g->value())->value())>>> { typedef decltype(f(g->value())->value()) U; auto p = new cDependentlyProduct<T,U,V>(g, f); return shared_ptr<cIterable<tuple<T,U>>>(p); }