#pragma once namespace iter { // Class which maps values returned by I iterator into iterators of type J // ,which // return value of type T, with function OP. // function. // T - type of return value // I - iterator type // J - iterator type returned from OP // OP - type of mapper function template class FlatMap : public IteratorBase { public: FlatMap() = delete; // FlatMap operation is designed to be used in chained calls which operate // on a // iterator. FlatMap will in that usecase receive other iterator by value // and // std::move is a optimization for it. FlatMap(I &&iter, OP &&op) : iter(std::move(iter)), op(std::move(op)) {} FlatMap(FlatMap &&m) : iter(std::move(m.iter)), op(std::move(m.op)), sub_iter(std::move(m.sub_iter)) { } ~FlatMap() final {} Option next() final { do { if (!sub_iter.is_present()) { auto item = iter.next(); if (item.is_present()) { sub_iter = Option(op(item.take())); } else { return Option(); } } auto item = sub_iter.get().next(); if (item.is_present()) { return std::move(item); } else { sub_iter.take(); } } while (true); } Count count() final { // TODO: Correct count, are at least correcter return iter.count(); } private: I iter; Option sub_iter; OP op; }; template auto make_flat_map(I &&iter, OP &&op) { // Compiler cant deduce type T and J. decltype is here to help with it. return FlatMap(std::move(iter), std::move(op)); } }