Почему boost filter_iterator имеет странную функцию make_filter_iterator?

После некоторой боли мне удалось взломать этот минимальный пример 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;
}

Это хорошо работает, но мне интересно, почему make_filter_iterator принимает numbers.end()? Я могу ошибаться, если использую его таким образом, я предположил это на примере массива C:
http://www.boost.org/doc/libs/1_53_0/libs/iterator/example/filter_iterator_example.cpp

2 ответа

Решение

Это объясняется в документах:

При пропуске элементов необходимо, чтобы адаптер фильтра знал, когда нужно остановиться, чтобы избежать выхода за пределы нижележащего диапазона. Поэтому итератор фильтра состоит из пары итераторов, указывающих диапазон элементов в нефильтрованной последовательности, которые необходимо пройти.

Из источника ниже вы можете увидеть, всегда ли они достигли конца в 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());
}

Также, как указал Алекс Чемберлен, конструкторы делают его необязательным при прохождении конечного итератора, например: filter_iterator(Iterator x, Iterator end = Iterator()); (при условии, что это значение по умолчанию). Таким образом, вы могли бы опустить numbers.end() из вашего кода при создании конечного итератора.

Если вы посмотрите на декларацию вашего make_filter_iterator шаблон, вы видите, это выглядит так:

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

В частности, вы видите, что последний параметр является параметром по умолчанию, и он установлен в Iterator() что означало бы, что это по умолчанию, и для некоторых типов итераторов он ведет себя как фактический end() итератор, который указывает один конец конца любого массива, то есть указывает на мусор.

Большинство типов контейнеров требуют фактического end() итератор для передачи.

Другие вопросы по тегам