Комментарии 5
Если итератор двунаправленный или прямого доступа, то над терминатором должна быть определена операция декремента, возвращающая итератор.
Тогда можно спокойно переделать фасад функции sort — пусть она будет sort(Iterator start, Sentinel finish), а внутри творит что хочет.
Казалось бы, арифметика над терминатором ломает строгость:
begin() — итератор
end() — терминатор
end()-1 — итератор
end()-1+1 — итератор?!
На самом деле, строгость сломана изначально:
begin()+1 — итератор
begin()+distance(begin(),end()) — итератор == end().
Так что можно расслабиться. Мы в С++, а не в Агде, здесь супер-пупер-типизацией от всего не защитишься.
От самых примитивных косяков, тем не менее, защититься можно. Для этого интерфейсы STL-алгоритмов вполне могут быть sort(Iterator begin, Sentinel end).
Единственно, — поскольку такое объявление слишком расслабляет (можно подсунуть границы не только из разных доменов, но и из разных типов), — придётся ввести проверку
которая показывает, относятся ли I и S к границам одного типа.
И, соответственно,
Тогда можно спокойно переделать фасад функции sort — пусть она будет sort(Iterator start, Sentinel finish), а внутри творит что хочет.
Казалось бы, арифметика над терминатором ломает строгость:
begin() — итератор
end() — терминатор
end()-1 — итератор
end()-1+1 — итератор?!
На самом деле, строгость сломана изначально:
begin()+1 — итератор
begin()+distance(begin(),end()) — итератор == end().
Так что можно расслабиться. Мы в С++, а не в Агде, здесь супер-пупер-типизацией от всего не защитишься.
От самых примитивных косяков, тем не менее, защититься можно. Для этого интерфейсы STL-алгоритмов вполне могут быть sort(Iterator begin, Sentinel end).
Единственно, — поскольку такое объявление слишком расслабляет (можно подсунуть границы не только из разных доменов, но и из разных типов), — придётся ввести проверку
template<class S> using bool const is_sentinel = __unspecified__;
template<class I> using bool const is_iterator = is_sentinel<I> && __unspecified__;
template<class I, class S> using bool const is_iterator_and_sentinel = is_iterator<I> && is_sentinel<S> && __unspecified__;
которая показывает, относятся ли I и S к границам одного типа.
И, соответственно,
template<class I, class S>
auto sort(I, S) -> typename enable_if< is_iterator_and_sentinel<I,S>, void >::type;
А можно в цикл статей добавить оглавление со ссылками на все части? Было бы удобней :)
Зарегистрируйтесь на Хабре, чтобы оставить комментарий
Интервалы в С++, часть 3: представляем инкременторы (Iterable)