Question

after some pain I managed to hack together this minimal example of boost filter_iterator

using namespace std;
std::function<bool(uint32_t)> stlfunc= [](uint32_t n){return n%3==0;};
int main()
{
   vector<uint32_t> numbers{11,22,33,44,55,66,77,3,6,9};
   auto start = boost::make_filter_iterator(stlfunc, numbers.begin(), numbers.end());
   auto end   = boost::make_filter_iterator(stlfunc, numbers.end()  , numbers.end());
   auto elem  = std::max_element(start,end);
   cout << *elem;
}

It works nice, but I wonder why the make_filter_iterator takes numbers.end()? I might be wrong to use it that way, I guestimated it from the C array example:
http://www.boost.org/doc/libs/1_53_0/libs/iterator/example/filter_iterator_example.cpp

Was it helpful?

Solution

That is explained in the docs:

When skipping over elements, it is necessary for the filter adaptor to know when to stop so as to avoid going past the end of the underlying range. A filter iterator is therefore constructed with pair of iterators indicating the range of elements in the unfiltered sequence to be traversed.

From the source below you can see the always check if they have reached the end in satisfy_predicate:

void increment()
{
    ++(this->base_reference());
    satisfy_predicate();
}

void satisfy_predicate()
{
    while (this->base() != this->m_end && !this->m_predicate(*this->base()))
        ++(this->base_reference());
}

Also, as pointed out by Alex Chamberlain, the constructors make it optional when passing the end iterator, for example: filter_iterator(Iterator x, Iterator end = Iterator()); (provided it is default constructible). So, you could omit numbers.end() from your code when constructing the end iterator.

OTHER TIPS

If you look at the declaration of your make_filter_iterator template, you see it looks like this:

template <class Predicate, class Iterator>
filter_iterator<Predicate,Iterator>
make_filter_iterator(Predicate f, Iterator x, Iterator end = Iterator());

Specifically you see that the last parameter is a default parameter, and it's set to Iterator() which would mean it's default contructed and for some types of iterator it behaves like actual end() iterator, which points one past the end of any array, ie it points to garbage.

Most container types do require an actual end() iterator to be passed.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top