2013-03-20 1 views
4

после некоторой боли мне удалось взломать вместе этот минимальный пример повышающего filter_iteratorЗачем нужен фильтр filter_iterator, имеет странную функцию make_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()? я мог бы неправильно использовать его таким образом, я guestimated это на примере массива C:
http://www.boost.org/doc/libs/1_53_0/libs/iterator/example/filter_iterator_example.cpp

ответ

7

Это объясняется в docs:

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

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

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

+0

Он также объясняет, что это необязательно, если базовый итератор по умолчанию является конструктивным (и представляет собой конец диапазона, который вы хотите). –

+0

im confused ... нормальные итераторы не знают, когда остановиться, так зачем делать filter_iterator? Я имею в виду, что вы не делаете этого (auto it = v.begin; it! = Std :: vector :: iterator(); ++ it) – NoSenseEtAl

+0

@NoSenseEtAl Не нужно ли UB увеличивать итератор 'end'? –

1

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

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

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

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

+1

'std :: vector :: const_iterator()! = std :: vector :: cend()' –

+0

Я не верю, что есть гарантия, что стандартная конструктор итераторов контейнера стандартной библиотеки будет равен конечному итератору. –

+0

@DaveS кажется, что вы правы, я соответствующим образом изменил свой ответ. –