Reputation: 19
template<typename Iterator>
struct Range {
using LazyIterator = Iterator; // required for accessing the used Iterator type from other locations
Iterator m_begin;
Iterator m_end;
auto begin() { return m_begin; }
auto end() { return m_end; }
};
template<typename Iterator>
Range(Iterator, Iterator) -> Range<Iterator>;
template<typename Iterator, typename Callable>
struct FilteringIterator : Iterator {
Callable callable;
using OriginalIterator = Iterator;
using t = typename OriginalIterator::value_type;
FilteringIterator(const Iterator begin, Callable callable):Iterator(begin),callable(callable){}
Iterator &get_orig_iter() { return ((Iterator &)*this); }
auto operator*() { return callable(*get_orig_iter()); }
};
auto filter = [](auto action) {
return [=]( auto &container) {
using Container = std::decay_t<decltype(container)>;
using Iterator = typename Container::iterator;
using actiontype = decltype(action);
using filter_iterator = FilteringIterator<Iterator, actiontype>;
return Range{filter_iterator{container.begin(),action}, filter_iterator{container.end(),action}};
};
};
I need a lazy iterator that will traverse over a range and filter it lazily. For example
auto v = std::vector<double>{};
auto odd_gen = views::odds();
for(int i=0; i<5; ++i)
v.push_back(odd_gen() * 2.5);
// v contains {2.5, 7.5, 12.5, 17.5, 22.5} here
new_line();
for(auto a : v | filter(greater_than(15))) // filter is applied lazily as the range is traversed
std::cout << a << std::endl;
// print { 17.5, 22.5} here
but it prints
{0,0,0,0,17.5,22.5}
I want it to only print 17.5, 22.5
how can I achieve that?
Upvotes: 1
Views: 306
Reputation: 7973
Your code never skips elements, it just transforms them. You need to make sure that when the operator*()
is invoked, it starts by advancing the iterator while callable
returns false
, and only then return the value pointed to by the Iterator
.
There are corner cases though you have to take care of. If the input ends with elements that don't match the filter, then you run into a problem. You also need to skip over all filtered out elements when operator++()
is called. And also think about the case where the filter would not match any elements of the input; in that case you must ensure that begin()
is equal to end()
.
Upvotes: 1