![]() |
![]() ![]() ![]() ![]() ![]() |
![]() |
Iterator Facade and AdaptorBoost , ,
|
Author: | Дэвид Абрахамс, Джереми Сик, Томас Витт | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Contact: | Итераторы играют важную роль в современном программировании на C++. Итератор — это центральная абстракция алгоритмов Стандартной библиотеки, позволяющая повторно использовать алгоритмы в самых разных контекстах. C++ Стандартная библиотека содержит широкий спектр полезных итераторов. Каждый стандартный контейнер поставляется с постоянными и изменяемыми итераторами.2, а также обратные версии тех же итераторов, которые пересекают контейнер в противоположном направлении. Стандарт также поставляетistream_iteratorиostream_iteratorдля чтения и записи в потокивставить_iterator,front_insert_iteratorиback_insert_iteratorдля вставки элементов в контейнеры иraw_storage_iteratorдля инициализации сырой памяти.
Несмотря на множество итераторов, поставляемых Стандартной библиотекой, очевидные и полезные итераторы отсутствуют, а создание новых типов итераторов по-прежнему является общей задачей для программистов C++. Литература документирует некоторые из них, например line_iteratorи Constant_iterator.. Абстракция итератора настолько сильна, что мы ожидаем, что программистам всегда придется изобретать новые типы итераторов. Хотя легко создать итераторы, которыепочтисоответствуют стандарту, требования итератора содержат тонкости, которые могут сделать создание итератора, которыйна самом делесоответствует довольно сложно. Кроме того, интерфейс итератора богат, содержит множество операторов, которые технически избыточны и утомительны для реализации. Для автоматизации повторяющейся работы по построению итераторов мы предлагаемiterator_facade, шаблон базового класса итератора, который обеспечивает богатый интерфейс стандартных итераторов и делегирует его реализацию членским функциям производного класса. В дополнение к уменьшению количества кода, необходимого для создания итератора,iterator_facadeтакже обеспечивает обнаружение ошибок в компиляции. Ошибки реализации итератора, которые часто остаются незамеченными, превращаются в ошибки времени компиляции, потому что реализация производного класса должна соответствовать ожиданиямiterator_facade. Общая схема построения итератора — адаптация одного итератора к формированию нового. Функциональность итератора состоит из четырех ортогональных аспектов: обход, опосредование, сравнение равенства и измерение расстояния. Адаптация старого итератора для создания нового часто экономит работу, потому что можно повторно использовать один аспект функциональности при переопределении другого. Например, Стандарт предоставляетreverse_iterator, который адаптирует любой Двунаправленный итератор, инвертируя его направление прохождения. Как и в случае простых итераторов, адаптеры итераторов, определенные вне стандарта, стали обычным явлением в литературе:
Чтобы удовлетворить потребность в конструировании адаптеров, мы предлагаем шаблон классаiterator_adaptor. Обоснованияiterator_adaptorслужат базовыми классами для новых итераторов, обеспечивая по умолчанию поведение пересылки всех операций на базовый итератор. Пользователь может выборочно заменить эти функции в классе производных итераторов. Это предложение также включает в себя ряд более специализированных адаптеров, таких какtransform_iterator, который применяет некоторые функции, определенные пользователем во время отсчета итератора. Impact on the StandardЭто предложение является чисто дополнением к стандартной библиотеке C++. Тем не менее, обратите внимание, что это предложение основано на предложении новых концепций итератора. DesignIterator ConceptsЭто предложение сформулировано с точки зрения новыхитераторовконцепций, предложенных вn1550, поскольку определяемые пользователем и особенно адаптированные итераторы страдают от хорошо известных проблем категоризации, которые присущи текущим категориям итераторов. Это предложение не зависит строго от предложенияn1550, поскольку существует прямое сопоставление между новыми и старыми категориями. Это предложение можно было бы переформулировать с помощью этого сопоставления, если быn1550не было принято. InteroperabilityВопрос о совместимости итератора плохо рассматривается в действующем стандарте. В настоящее время имеются два сообщения о дефектах, которые касаются вопросов совместимости. Выпуск179касается того, что мутируемые типы контейнерных итераторов должны быть только конвертируемыми в соответствующие типы постоянных итераторов, но объекты этих типов не обязаны взаимодействовать в выражениях сравнения или вычитания. Эта ситуация утомительна на практике и не соответствует тому, как работают типы. В этом предложении реализовано предложенное решение о выпуске179, как и в большинстве стандартных реализаций библиотек в настоящее время. Другими словами, если итератор типа А имеет неявное или определенное пользователем преобразование в итератор типа В, типы итератора являются взаимодействующими и доступен обычный набор операторов. Проблема280касается нынешнего отсутствия совместимости между типами реверсивных итераторов. Предлагаемый новый шаблон reverse_iterator решает проблемы, поднятые в 280 году. Он обеспечивает желаемую совместимость без введения нежелательных перегрузок. Iterator FacadeВ то время как интерфейс итератора богат, есть базовое подмножество интерфейса, которое необходимо для всей функциональности. Мы определили следующие основные модели поведения итераторов:
В дополнение к вышеперечисленным видам поведения, основные элементы интерфейса включают связанные типы, подвергаемые через итераторы признакам:value_type,reference,difference_typeиiterator_category. Фасад итератора использует Curiously Recurring Template Pattern (CRTP)[Cop95], чтобы пользователь мог указать поведениеiterator_facadeв производном классе. Бывшие проекты использовали объекты политики для определения поведения, но этот подход был отброшен по нескольким причинам:
UsageПользовательiterator_facadeполучает свой класс итератора из специализацииiterator_facadeи проходит класс производного итератора какiterator_facadeпервый параметр шаблона. Порядок других параметров шаблона был тщательно выбран, чтобы воспользоваться полезными по умолчанию. Например, при определении итератора с постоянным значением l, пользователь может передать конст-квалифицированную версию параметразначения итераторакакитератора_фасадазначенияи опустить параметр.Ссылкапараметр, который следует. Полученный класс итератора должен определять функции члена, реализующие основные модели поведения итератора. В следующей таблице описаны выражения, которые должны быть действительными в зависимости от категории производного типа итератора. Эти функции элементов кратко описаны ниже и более подробно в требованиях к фасаду итератора.
В дополнение к реализации основных функций интерфейса итератор, полученный изiterator_facade, обычно определяет несколько конструкторов. Чтобы смоделировать любую из стандартных концепций итератора, итератор должен иметь конструктор копий. Кроме того, если тип итератораXпредназначен для автоматического взаимодействия с другим типом итератораY(как с постоянными и изменчивыми итераторами), то должно быть неявное преобразование изXвYили изYвX(но не оба), как правило, реализованное в качестве конструктора преобразования. Наконец, если итератор предназначен для моделирования итератора переднего поворота или более усовершенствованной концепции итератора, требуется конструктор по умолчанию. Iterator Core Accessiterator_facadeи реализации оператора должны иметь возможность доступа к основным функциям-членам в производном классе. Публикация основных функций-членов раскрывает пользователю детали реализации. Используемый здесь дизайн гарантирует, что детали реализации не отображаются в публичном интерфейсе производного типа итератора. Предотвращение прямого доступа к основным функциям имеет два преимущества. Во-первых, у пользователя нет возможности случайно использовать функцию члена итератора, когда был предназначен элемент типа значения. В прошлом это было проблемой с интеллектуальными реализациями указателей. Второе и главное преимущество заключается в том, что реализаторы библиотек могут свободно обмениваться ручной реализацией итератора на реализацию на основеiterator_facade, не опасаясь взлома кода, который имел доступ к функциям публичного ядра. В наивной реализации сохранение в тайне основных функций членов производного класса потребует от него предоставления дружбыiterator_facadeи каждому из семи операторов. Чтобы уменьшить бремя ограничения доступа, предоставляетсяiterator_core_access, класс, который действует как шлюз к функциям основного члена в классе производного итератора. Автору производного класса нужно только предоставить дружбуiterator_core_access, чтобы его основные функции члена были доступны библиотеке. iterator_core_accessобычно реализуется в виде пустого класса, содержащего только частные статические функции-члены, которые вызывают функции-ядра итератора. Однако нет необходимости стандартизировать протокол шлюза. Обратите внимание, что даже еслиитератор_core_accessиспользует публичные функции-члены, это не откроет лазейку безопасности, поскольку каждая функция-ядро сохраняет инварианты итератора. operator[]Оператор индексации для обобщенного итератора представляет особые проблемы. Итератор случайного доступаоператортребуется только вернуть что-то конвертируемое в егозначение_тип. Требование, чтобы он возвращал значение l, исключало бы в настоящее время законные итераторы случайного доступа, которые содержат указанное значение в элементе данных (например,подсчёт_iterator), потому что* (p+n)является ссылкой на временный итераторp+n, который разрушается, когдаоператор []возвращается. Письменные итераторы, построенные с помощьюiterator_facade, реализуют семантику, требуемую предпочтительным разрешениемвыпуска 299и принятую предложениемn1550: результатp[n]является объектом, конвертируемым в итераторзначение_тип, иp [n]xэквивалентен* [p+=x(Примечание: Этот объект результата может быть реализован в качестве прокси, содержащего копиюp+n. Этот подход будет работать должным образом для любого итератора случайного доступа независимо от других деталей его реализации. Пользователь, который знает больше о реализации своего итератора, может свободно реализовать оператора, который возвращает значение l в классе производного итератора; он будет скрывать тот, который поставляетсяiterator_facadeот клиентов своего итератора. operator->Тип ссылкичитаемого итератора (и сегодняшнего итератора ввода) на самом деле не обязательно должен быть эталоном, если он конвертируем в значениеитератора. Однако, когдазначение_типявляется классом, все равно должна быть возможность доступа к членам черезоператора->. Поэтому итератор, чейэталонныйтип фактически не является эталонным, должен возвращать прокси-сервер, содержащий копию указанной величины от егооператора->. Типы возврата дляiterator_facade'sоператора->иоператора []явно не указаны. Вместо этого эти типы описаны в терминах набора требований, которые должны быть удовлетворены реализациейiterator_facade.
Iterator AdaptorШаблон классаiterator_adaptorадаптирует некоторыйБазовый3тип для создания нового итератора. Обоснованияiterator_adaptorполучены из соответствующего инстанциированияiterator_facadeи реализуют основные модели поведения с точки зренияBaseтипа. По сути,iterator_adaptorпросто перенаправляет все операции на экземпляр типаBase, который он хранит в качестве члена.
Пользовательiterator_adaptorсоздает класс, полученный из инстанциацииiterator_adaptor, а затем выборочно переопределяет некоторые из основных функций-членов, описанных в таблице основных требованийiterator_facade. ТипBaseне должен удовлетворять всем требованиям к итератору; ему требуется только поддержка операций, используемых основными функциями интерфейсаiterator_adaptor, которые не были переопределены в производном классе пользователя. Несколько параметров шаблонаiterator_adaptorпо умолчаниюиспользуют_default. Это позволяет пользователю использовать параметр по умолчанию, даже если он хочет указать параметр позже в списке параметров. Также по умолчанию для соответствующих связанных типов несколько сложны, поэтому для их вычисления требуется метапрограммирование, иuse_defaultможет помочь упростить реализацию. Наконец, идентификатор типаuse_defaultне остается неуказанным, поскольку спецификация помогает подчеркнуть, чтоСсылочныйпараметр шаблона не всегда может быть идентичен ссылочномутипу итератораи не позволит пользователям совершать ошибки на основе этого предположения. Specialized AdaptorsЭто предложение также содержит несколько примеров специализированных адаптеров, которые были легко реализованы с использованиемiterator_adaptor:
Основываясь на примерах в библиотеке Boost, пользователи создали много новых адаптеров, среди которых адаптер перестановки, который применяет некоторую перестановку к итератору случайного доступа, и шагающий адаптер, который адаптирует итератор случайного доступа, умножая свою единицу движения на постоянный фактор. Кроме того, библиотека Boost Graph Library (BGL) использует адаптеры итераторов для адаптации других графовых библиотек, таких как LEDAи Stanford GraphBase, к интерфейсу BGL (для которого требуются итераторы, соответствующие стандарту C++). Proposed TextHeader <iterator_helper> synopsis [lib.iterator.helper.synopsis]struct use_default; struct iterator_core_access { /* implementation detail */ }; template < class Derived , class Value , class CategoryOrTraversal , class Reference = Value& , class Difference = ptrdiff_t > class iterator_facade; template < class Derived , class Base , class Value = use_default , class CategoryOrTraversal = use_default , class Reference = use_default , class Difference = use_default > class iterator_adaptor; template < class Iterator , class Value = use_default , class CategoryOrTraversal = use_default , class Reference = use_default , class Difference = use_default > class indirect_iterator; template <class Dereferenceable> struct pointee; template <class Dereferenceable> struct indirect_reference; template <class Iterator> class reverse_iterator; template < class UnaryFunction , class Iterator , class Reference = use_default , class Value = use_default > class transform_iterator; template <class Predicate, class Iterator> class filter_iterator; template < class Incrementable , class CategoryOrTraversal = use_default , class Difference = use_default > class counting_iterator; template <class UnaryFunction> class function_output_iterator; Iterator facade [lib.iterator.facade]iterator_facadeявляется шаблоном базового класса, который реализует интерфейс стандартных итераторов с точки зрения нескольких основных функций и связанных типов, которые должны поставляться производным классом итераторов. Class template iterator_facadetemplate < class Derived , class Value , class CategoryOrTraversal , class Reference = Value& , class Difference = ptrdiff_t > class iterator_facade { public: typedef remove_const<Value>::type value_type; typedef Reference reference; typedef Value* pointer; typedef Difference difference_type; typedef /* see below */ iterator_category; reference operator*() const; /* see below */ operator->() const; /* see below */ operator[](difference_type n) const; Derived& operator++(); Derived operator++(int); Derived& operator--(); Derived operator--(int); Derived& operator+=(difference_type n); Derived& operator-=(difference_type n); Derived operator-(difference_type n) const; protected: typedef iterator_facade iterator_facade_; }; // Comparison operators template <class Dr1, class V1, class TC1, class R1, class D1, class Dr2, class V2, class TC2, class R2, class D2> typename enable_if_interoperable<Dr1,Dr2,bool>::type // exposition operator ==(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs, iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs); template <class Dr1, class V1, class TC1, class R1, class D1, class Dr2, class V2, class TC2, class R2, class D2> typename enable_if_interoperable<Dr1,Dr2,bool>::type operator !=(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs, iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs); template <class Dr1, class V1, class TC1, class R1, class D1, class Dr2, class V2, class TC2, class R2, class D2> typename enable_if_interoperable<Dr1,Dr2,bool>::type operator <(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs, iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs); template <class Dr1, class V1, class TC1, class R1, class D1, class Dr2, class V2, class TC2, class R2, class D2> typename enable_if_interoperable<Dr1,Dr2,bool>::type operator <=(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs, iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs); template <class Dr1, class V1, class TC1, class R1, class D1, class Dr2, class V2, class TC2, class R2, class D2> typename enable_if_interoperable<Dr1,Dr2,bool>::type operator >(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs, iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs); template <class Dr1, class V1, class TC1, class R1, class D1, class Dr2, class V2, class TC2, class R2, class D2> typename enable_if_interoperable<Dr1,Dr2,bool>::type operator >=(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs, iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs); // Iterator difference template <class Dr1, class V1, class TC1, class R1, class D1, class Dr2, class V2, class TC2, class R2, class D2> /* see below */ operator-(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs, iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs); // Iterator addition template <class Dr, class V, class TC, class R, class D> Derived operator+ (iterator_facade<Dr,V,TC,R,D> const&, typename Derived::difference_type n); template <class Dr, class V, class TC, class R, class D> Derived operator+ (typename Derived::difference_type n, iterator_facade<Dr,V,TC,R,D> const&); The iterator_category member of iterator_facade is iterator-category(CategoryOrTraversal, value_type, reference) гдеитератор-категорияопределена следующим образом: iterator-category(C,R,V) := if (C is convertible to std::input_iterator_tag || C is convertible to std::output_iterator_tag ) return C else if (C is not convertible to incrementable_traversal_tag) the program is ill-formed else return a type X satisfying the following two constraints: 1. X is convertible to X1, and not to any more-derived type, where X1 is defined by: if (R is a reference type && C is convertible to forward_traversal_tag) { if (C is convertible to random_access_traversal_tag) X1 = random_access_iterator_tag else if (C is convertible to bidirectional_traversal_tag) X1 = bidirectional_iterator_tag else X1 = forward_iterator_tag } else { if (C is convertible to single_pass_traversal_tag && R is convertible to V) X1 = input_iterator_tag else X1 = C } 2. category-to-traversal(X) is convertible to the most derived traversal tag type to which X is also convertible, and not to any more-derived traversal tag type. [Примечание: намерение состоит в том, чтобы позволитьiterator_categoryбыть одним из пяти исходных тегов категории, когда конвертируемость в один из тегов обхода не добавит информации] Шаблонenable_if_interoperable, используемый выше, предназначен для экспозиции. Операторы-члены должны находиться только в наборе перегрузок при условии, что производные типыDr1иDr2являются взаимодействующими, что означает, что по меньшей мере один из типов является конвертируемым в другой. Подходпозволяет_if_interoperableиспользовать SFINAE для вывода операторов из набора перегрузок, когда типы не совместимы. Операторы должны вести себятак, как есливключить_if_интероперабельностьбыло определено: template <bool, typename> enable_if_interoperable_impl {}; template <typename T> enable_if_interoperable_impl<true,T> { typedef T type; }; template<typename Dr1, typename Dr2, typename T> struct enable_if_interoperable : enable_if_interoperable_impl< is_convertible<Dr1,Dr2>::value || is_convertible<Dr2,Dr1>::value , T > {}; iterator_facade RequirementsВ следующей таблице описаны типичные действительные выражения поитератор_фасад'sПроизводныйпараметр, в зависимости от концепции(ей) итератора, которую он будет моделировать. Операции в первой колонке должны быть доступны для членских функций классаiterator_core_access. Кроме того,static_cast В приведенной ниже таблицеFaaX,bиcconst,nF::difference_type,yявляется постоянным объектом однопроходного итератора типа, взаимодействующего сX, иzzявляется постоянным объектом случайного доступа, пересекающегося с итератором типа iterator_facade Core Operations
iterator_facade operationsОперации в этом разделе описаны в терминах операций на базовом интерфейсе.Получено, которое может быть недоступным (т.е. частным). Реализация должна обеспечивать доступ к этим операциям через функции-члены классаiterator_core_access. эталоноператор*()const;
оператор->()const;(см.ниже)
unspecified operator[](difference_type n) const;
Derived&operator++();
Выводитсяоператор++(int);
Производный &оператор--();
Производныйоператор - (int);
Производный &оператор +=(разница_типn);
Производный &оператор-=(разница_типn);
Выводитсяоператор-(различие_типn)const;
template <class Dr, class V, class TC, class R, class D> Derived operator+ (iterator_facade<Dr,V,TC,R,D> const&, typename Derived::difference_type n); template <class Dr, class V, class TC, class R, class D> Derived operator+ (typename Derived::difference_type n, iterator_facade<Dr,V,TC,R,D> const&);
template <class Dr1, class V1, class TC1, class R1, class D1, class Dr2, class V2, class TC2, class R2, class D2> typename enable_if_interoperable<Dr1,Dr2,bool>::type operator ==(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs, iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs);
template <class Dr1, class V1, class TC1, class R1, class D1, class Dr2, class V2, class TC2, class R2, class D2> typename enable_if_interoperable<Dr1,Dr2,bool>::type operator !=(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs, iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs);
template <class Dr1, class V1, class TC1, class R1, class D1, class Dr2, class V2, class TC2, class R2, class D2> typename enable_if_interoperable<Dr1,Dr2,bool>::type operator <(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs, iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs);
template <class Dr1, class V1, class TC1, class R1, class D1, class Dr2, class V2, class TC2, class R2, class D2> typename enable_if_interoperable<Dr1,Dr2,bool>::type operator <=(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs, iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs);
template <class Dr1, class V1, class TC1, class R1, class D1, class Dr2, class V2, class TC2, class R2, class D2> typename enable_if_interoperable<Dr1,Dr2,bool>::type operator >(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs, iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs);
template <class Dr1, class V1, class TC1, class R1, class D1, class Dr2, class V2, class TC2, class R2, class D2> typename enable_if_interoperable<Dr1,Dr2,bool>::type operator >=(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs, iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs);
template <class Dr1, class V1, class TC1, class R1, class D1, class Dr2, class V2, class TC2, class R2, class D2> typename enable_if_interoperable<Dr1,Dr2,difference>::type operator -(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs, iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs);
Iterator adaptor [lib.iterator.adaptor]Каждая специализация шаблона классаiterator_adaptorпроисходит от специализацииiterator_facade. Основные функции интерфейса, ожидаемыеiterator_facade, реализованы с точки зренияiterator_adaptorбазовогопараметра шаблона. Класс, полученный изiterator_adaptor, обычно переопределяет некоторые основные функции интерфейса для адаптации поведения типаBase. Является ли производная модель класса какой-либо из стандартных концепций итератора зависит от операций, поддерживаемых типомБазаи какие основные функции интерфейсаитератор_фасадпереопределяются в классеПроизводный. Class template iterator_adaptortemplate < class Derived , class Base , class Value = use_default , class CategoryOrTraversal = use_default , class Reference = use_default , class Difference = use_default > class iterator_adaptor : public iterator_facade<Derived, V', C', R', D'> // see details { friend class iterator_core_access; public: iterator_adaptor(); explicit iterator_adaptor(Base const& iter); typedef Base base_type; Base const& base() const; protected: typedef iterator_adaptor iterator_adaptor_; Base const& base_reference() const; Base& base_reference(); private: // Core iterator interface for iterator_facade. typename iterator_adaptor::reference dereference() const; template < class OtherDerived, class OtherIterator, class V, class C, class R, class D > bool equal(iterator_adaptor<OtherDerived, OtherIterator, V, C, R, D> const& x) const; void advance(typename iterator_adaptor::difference_type n); void increment(); void decrement(); template < class OtherDerived, class OtherIterator, class V, class C, class R, class D > typename iterator_adaptor::difference_type distance_to( iterator_adaptor<OtherDerived, OtherIterator, V, C, R, D> const& y) const; private: Base m_iterator; // exposition only }; iterator_adaptor requirementsstatic_cast iterator_adaptor base class parametersV',C',R'иD'параметрыитератора_фасада, используемого в качестве базового класса в резюмеитератора_адапторавыше, определяются следующим образом: V' = if (Value is use_default) return iterator_traits<Base>::value_type else return Value C' = if (CategoryOrTraversal is use_default) return iterator_traversal<Base>::type else return CategoryOrTraversal R' = if (Reference is use_default) if (Value is use_default) return iterator_traits<Base>::reference else return Value& else return Reference D' = if (Difference is use_default) return iterator_traits<Base>::difference_type else return Difference iterator_adaptor public operationsiterator_adaptor();
эксплицитныйитератор_адаптор(Базаconst&итер;
Базаconst&база []const;
iterator_adaptor protected member functionsБазаconst&base_reference()const;
Base&base_reference();
iterator_adaptor private member functionsимя типаитератор_адаптор:: ссылкассылкаconst;
template < class OtherDerived, class OtherIterator, class V, class C, class R, class D > bool equal(iterator_adaptor<OtherDerived, OtherIterator, V, C, R, D> const& x) const;
voidadvance(имяiterator_adaptor::difference_typen);
voidincrement();
voiddecrement();
template < class OtherDerived, class OtherIterator, class V, class C, class R, class D > typename iterator_adaptor::difference_type distance_to( iterator_adaptor<OtherDerived, OtherIterator, V, C, R, D> const& y) const;
Specialized adaptors [lib.iterator.special.adaptors]enable_if_convertible template <bool> enable_if_convertible_impl {}; template <> enable_if_convertible_impl<true> { struct type; }; template<typename From, typename To> struct enable_if_convertible : enable_if_convertible_impl<is_convertible<From,To>::value> {}; Если выражение, отличное от аргумента по умолчанию, используется для подачи значения параметра функции, тип которого записан в терминахenable_if_convertible, программа плохо сформирована, диагностика не требуется. Примечание:Подходпозволяетиспользовать SFINAE для вывода конструктора из набора перегрузок, когда типы не являются неявно конвертируемыми. ] Indirect iteratorindirect_iteratorадаптирует итератор, применяядополнительныйdereference внутриоператора*(). Например, этот адаптер итератора позволяет просматривать контейнер указателей (например,list Class template pointeetemplate <class Dereferenceable> struct pointee { typedef /* see below */ type; };
типопределяется по следующему алгоритму, гдеxявляется объектом типаСсылка: if ( ++x is ill-formed ) { return ``Dereferenceable::element_type`` } else if (``*x`` is a mutable reference to std::iterator_traits<Dereferenceable>::value_type) { return iterator_traits<Dereferenceable>::value_type } else { return iterator_traits<Dereferenceable>::value_type const } Class template indirect_referencetemplate <class Dereferenceable> struct indirect_reference { typedef /* see below */ type; };
типопределяется по следующему алгоритму, гдеxявляется объектом типаСсылка: if ( ++x is ill-formed ) return ``pointee<Dereferenceable>::type&`` else std::iterator_traits<Dereferenceable>::reference Class template indirect_iteratortemplate < class Iterator , class Value = use_default , class CategoryOrTraversal = use_default , class Reference = use_default , class Difference = use_default > class indirect_iterator { public: typedef /* see below */ value_type; typedef /* see below */ reference; typedef /* see below */ pointer; typedef /* see below */ difference_type; typedef /* see below */ iterator_category; indirect_iterator(); indirect_iterator(Iterator x); template < class Iterator2, class Value2, class Category2 , class Reference2, class Difference2 > indirect_iterator( indirect_iterator< Iterator2, Value2, Category2, Reference2, Difference2 > const& y , typename enable_if_convertible<Iterator2, Iterator>::type* = 0 // exposition ); Iterator const& base() const; reference operator*() const; indirect_iterator& operator++(); indirect_iterator& operator--(); private: Iterator m_iterator; // exposition }; Типы членовdirect_iteratorопределяются в соответствии со следующим псевдокодом, гдеVявляетсяiterator_traits if (Value is use_default) then typedef remove_const<pointee<V>::type>::type value_type; else typedef remove_const<Value>::type value_type; if (Reference is use_default) then if (Value is use_default) then typedef indirect_reference<V>::type reference; else typedef Value& reference; else typedef Reference reference; if (Value is use_default) then typedef pointee<V>::type* pointer; else typedef Value* pointer; if (Difference is use_default) typedef iterator_traits<Iterator>::difference_type difference_type; else typedef Difference difference_type; if (CategoryOrTraversal is use_default) typedef iterator-category ( iterator_traversal<Iterator>::type,``reference``,``value_type`` ) iterator_category; else typedef iterator-category ( CategoryOrTraversal,``reference``,``value_type`` ) iterator_category; indirect_iterator requirementsВыражение*v, гдеvявляется объектомiterator_traits [Примечание: существуют дополнительные требования кiterator_traits indirect_iterator modelsВ дополнение к понятиям, указаннымiterator_categoryиiterator_traversal
direct_iterator indirect_iterator operationsВ дополнение к операциям, требуемым концепциями, описанными выше, специализацииdirect_iteratorобеспечивают следующие операции. direct_iterator();
direct_iterator(Iteratorx);
template < class Iterator2, class Value2, unsigned Access, class Traversal , class Reference2, class Difference2 > indirect_iterator( indirect_iterator< Iterator2, Value2, Access, Traversal, Reference2, Difference2 > const& y , typename enable_if_convertible<Iterator2, Iterator>::type* = 0 // exposition );
Итераторconst&base()const;
эталоноператор*()const;
direct_iterator&operator++();
direct_iterator&operator--();
Reverse iteratorАдаптер обратного итератора итерирует через адаптированный диапазон итератора в противоположном направлении. Class template reverse_iteratortemplate <class Iterator> class reverse_iterator { public: typedef iterator_traits<Iterator>::value_type value_type; typedef iterator_traits<Iterator>::reference reference; typedef iterator_traits<Iterator>::pointer pointer; typedef iterator_traits<Iterator>::difference_type difference_type; typedef /* see below */ iterator_category; reverse_iterator() {} explicit reverse_iterator(Iterator x) ; template<class OtherIterator> reverse_iterator( reverse_iterator<OtherIterator> const& r , typename enable_if_convertible<OtherIterator, Iterator>::type* = 0 // exposition ); Iterator const& base() const; reference operator*() const; reverse_iterator& operator++(); reverse_iterator& operator--(); private: Iterator m_iterator; // exposition }; ЕслиИтератормодели Random Access Traversal Iterator и Readable Lvalue Iterator, тоитератор_категорияконвертируется вслучайный_access_iterator_tag. В противном случае, еслиИтератормодели Двунаправленный Траверсальный Итератор и Считываемый Итератор Значения, тоитератор_категорияявляется конвертируемым вдвунаправленный_iterator_tag. В противном случаеитератор_категорияпреобразуется ввходной_iterator_tag. reverse_iterator requirementsИтератордолжен быть моделью Двунаправленного Траверсального Итератора. Типiterator_traits reverse_iterator modelsСпециализацияreverse_iteratorмоделирует те же концепции обхода итератора и доступа итератора, смоделированные его.Итератораргумент. Кроме того, он может моделировать старые концепции итератора, указанные в следующей таблице:
reverse_iterator reverse_iterator operationsВ дополнение к операциям, требуемым концепциями, смоделированнымиreverse_iterator,reverse_iterator, предусмотрены следующие операции. reverse_iterator();
явныйобратный_iterator(Iteratorx);
template<class OtherIterator> reverse_iterator( reverse_iterator<OtherIterator> const& r , typename enable_if_convertible<OtherIterator, Iterator>::type* = 0 // exposition );
Итераторconst&base()const;
эталоноператор*()const;
Iterator tmp = m_iterator; return *--tmp; reverse_iterator&operator++();
reverse_iterator&operator--();
Transform iteratorПреобразующий итератор адаптирует итератор, изменяя оператор, чтобы применить объект функции к результату отступления от итератора и возврата результата. Class template transform_iteratortemplate <class UnaryFunction, class Iterator, class Reference = use_default, class Value = use_default> class transform_iterator { public: typedef /* see below */ value_type; typedef /* see below */ reference; typedef /* see below */ pointer; typedef iterator_traits<Iterator>::difference_type difference_type; typedef /* see below */ iterator_category; transform_iterator(); transform_iterator(Iterator const& x, UnaryFunction f); template<class F2, class I2, class R2, class V2> transform_iterator( transform_iterator<F2, I2, R2, V2> const& t , typename enable_if_convertible<I2, Iterator>::type* = 0 // exposition only , typename enable_if_convertible<F2, UnaryFunction>::type* = 0 // exposition only ); UnaryFunction functor() const; Iterator const& base() const; reference operator*() const; transform_iterator& operator++(); transform_iterator& operator--(); private: Iterator m_iterator; // exposition only UnaryFunction m_f; // exposition only }; ЕслиСсылкаявляетсяuse_default, тоэталончленtransform_iteratorявляетсярезультатом_of Еслизначениеявляетсяuse_default, тозначение_typeчленудалите_cv ЕслиИтератормодели Считываемый Итератор Значения и еслиИтератормодели Случайный Доступ Поперечный Итератор, тоитератор_категорияконвертируем вслучайный_access_iterator_tag. В противном случае, еслиИтератормодели Двунаправленный Траверсальный Итератор, тоитератор_категориябинаправленный_iterator_tag.В противном случаеитератор_категорияявляется конвертируемым впередний_iterator_tag.ЕслиИтераторне моделирует Считываемый Lvalue Итератор, тоитератор_категорияявляется конвертируемым ввход_iterator_tag. transform_iterator requirementsТипUnaryFunctionдолжен быть уступчивым, копируемым, конструируемым, а выражениеf(*i)должно быть действительным, еслиfявляется объектом типа,iявляется объектом типаИтератор, и где типf(*i)должен бытьрезультатом_of АргументИтератордолжен моделировать читаемый итератор. transform_iterator modelsПолученный в результатеTransform_iteratorмоделирует наиболее совершенную из следующих моделей, которая также смоделированаIterator.
МодельTransform_iteratorявляется наиболее усовершенствованной стандартной концепцией обхода, которая смоделирована.Итератораргумент. ЕслиTransform_iteratorявляется моделью Readable Lvalue Iterator, то он моделирует следующие оригинальные концепции итератора в зависимости от того, чтоИтератормодели аргументов.
Еслипреобразовать_iteratorмодели Writable Lvalue Iterator, то это изменяемый итератор (как определено в старых требованиях к итератору). Transform_iterator transform_iterator operationsВ дополнение к операциям, требуемым концепциями, смоделированнымиTransform_iterator,Transform_iteratorобеспечивает следующие операции. Transform_iterator();
transform_iterator(Iteratorconst&x,UnaryFunctionf);
template<class F2, class I2, class R2, class V2> transform_iterator( transform_iterator<F2, I2, R2, V2> const& t , typename enable_if_convertible<I2, Iterator>::type* = 0 // exposition only , typename enable_if_convertible<F2, UnaryFunction>::type* = 0 // exposition only );
UnaryFunctionfunctor()const;
Итераторconst&base()const;
эталоноператор*()const;
transform_iterator&operator++();
transform_iterator&operator--();
Filter iteratorАдаптер фильтратора создает вид диапазона итератора, в котором некоторые элементы диапазона пропущены. Объект функции предиката контролирует, какие элементы пропущены. Когда предикат применяется к элементу, если он возвращаетистинное, то элемент сохраняется, и если он возвращаетложное, то элемент пропускается. При пропуске элементов адаптер фильтра должен знать, когда остановиться, чтобы избежать прохождения конца базового диапазона. Поэтому фильтрующий итератор построен с парой итераторов, указывающих диапазон элементов в нефильтрованной последовательности для прохождения. Class template filter_iteratortemplate <class Predicate, class Iterator> class filter_iterator { public: typedef iterator_traits<Iterator>::value_type value_type; typedef iterator_traits<Iterator>::reference reference; typedef iterator_traits<Iterator>::pointer pointer; typedef iterator_traits<Iterator>::difference_type difference_type; typedef /* see below */ iterator_category; filter_iterator(); filter_iterator(Predicate f, Iterator x, Iterator end = Iterator()); filter_iterator(Iterator x, Iterator end = Iterator()); template<class OtherIterator> filter_iterator( filter_iterator<Predicate, OtherIterator> const& t , typename enable_if_convertible<OtherIterator, Iterator>::type* = 0 // exposition ); Predicate predicate() const; Iterator end() const; Iterator const& base() const; reference operator*() const; filter_iterator& operator++(); private: Predicate m_pred; // exposition only Iterator m_iter; // exposition only Iterator m_end; // exposition only }; ЕслиИтератормодели Считываемый Итератор Значения и Двунаправленный Траверсальный Итератор, тоитератор_категорияконвертируется вstd::bidirectional_iterator_tag. В противном случае, еслиИтератормодели Считываемый итератор Lvalue и Итератор переднего хода, тоитератор_категорияявляется конвертируемым вstd::forward_iterator_tag. В противном случаеитератор_категорияявляется конвертируемым вstd::input_iterator_tag. filter_iterator requirementsАргументИтератордолжен соответствовать требованиям Итератора для чтения и Итератора для одиночного прохода или он должен соответствовать требованиям Итератора ввода. АргументПредикатадолжен быть приемлемым, копируемым конструируемым, а выражениеp(x)должно быть действительным, еслиpявляется объектом типаПредиката,xявляется объектом типаитератора_traits filter_iterator modelsПредставления о том, чтомодели фильтра-итераторазависят от того, какие понятияИтератормодели аргументов, как указано в следующих таблицах.
filter_iterator filter_iterator operationsВ дополнение к этим операциям, требуемым концепциями, которыемодели filter_iterator,фильтр_iteratorобеспечивают следующие операции. filter_iterator();
filter_iterator (Предсказательf,Итераторx,Итераторконец=Итератор());
filter_iterator (Итераторx,Итераторконец=Итератор());
template <class OtherIterator> filter_iterator( filter_iterator<Predicate, OtherIterator> const& t , typename enable_if_convertible<OtherIterator, Iterator>::type* = 0 // exposition );``
ПредикатПредикат()const;
Итераторконецконст;
Итераторconst&base()const;
эталоноператор*()const;
filter_iterator&operator++();
Counting iteratorCounting_iteratorадаптирует объект путем добавления оператора, который возвращает текущее значение объекта. Все остальные операции итератора направляются на адаптированный объект. Class template counting_iteratortemplate < class Incrementable , class CategoryOrTraversal = use_default , class Difference = use_default > class counting_iterator { public: typedef Incrementable value_type; typedef const Incrementable& reference; typedef const Incrementable* pointer; typedef /* see below */ difference_type; typedef /* see below */ iterator_category; counting_iterator(); counting_iterator(counting_iterator const& rhs); explicit counting_iterator(Incrementable x); Incrementable const& base() const; reference operator*() const; counting_iterator& operator++(); counting_iterator& operator--(); private: Incrementable m_inc; // exposition }; Если аргументРазницаявляетсяUse_default, тоРазница_typeявляется неопределенным подписанным интегральным типом. Иначеdifference_type—Difference. итератор_категорияопределяется по следующему алгоритму: if (CategoryOrTraversal is not use_default) return CategoryOrTraversal else if (numeric_limits<Incrementable>::is_specialized) return iterator-category( random_access_traversal_tag, Incrementable, const Incrementable&) else return iterator-category( iterator_traversal<Incrementable>::type, Incrementable, const Incrementable&)
counting_iterator requirementsДополняемыйаргумент должен быть конструктивен и приемлем. Еслиiterator_categoryконвертируется вforward_iterator_tagилиforward_traversal_tag, то должно быть хорошо сформировано следующее: Incrementable i, j; ++i; // pre-increment i == j; // operator equal Еслиiterator_categoryконвертируется вbidirectional_iterator_tagилиbidirectional_traversal_tag, то должно быть также хорошо сформировано следующее выражение: --i Еслиiterator_categoryконвертируется вrandom_access_iterator_tagилиrandom_access_traversal_tag, то должно быть также действительным следующее: counting_iterator::difference_type n; i += n; n = i - j; i < j; counting_iterator modelsСпециализацииCounting_iteratorмодель Readable Lvalue Iterator. Кроме того, они моделируют понятия, соответствующие тегам итератора, к которым ихитератор_категорияявляется конвертируемым. Кроме того, еслиCategoryOrTraversalне являетсяuse_default, тоcounting_iteratorмоделирует концепцию, соответствующую тегу итератораКатегорияПутешествия. В противном случае, еслиnumeric_limits Counting_iterator counting_iterator operationsВ дополнение к операциям, требуемым концепциями, смоделированнымиCounting_iterator,Counting_iteratorобеспечивает следующие операции. Counting_iterator();
counting_iteratorconst&rhs;
эксплицитныйсчетчик_iterator(Incrementablex);
эталоноператор*()const;
counting_iterator&operator++();
counting_iterator&operator--();
const&base()const;
Function output iteratorАдаптер итератора вывода функции облегчает создание пользовательских итераторов вывода. Адаптер выполняет унарную функцию и создает модель Output Iterator. Каждый элемент, назначенный выходному итератору, передается в качестве аргумента унарной функции. Мотивация этого итератора заключается в том, что создание соответствующего выходного итератора нетривиально, особенно потому, что для правильной реализации обычно требуется прокси-объект. Header#include <boost/function_output_iterator.hpp> template <class UnaryFunction> class function_output_iterator { public: typedef std::output_iterator_tag iterator_category; typedef void value_type; typedef void difference_type; typedef void pointer; typedef void reference; explicit function_output_iterator(); explicit function_output_iterator(const UnaryFunction& f); /* see below */ operator*(); function_output_iterator& operator++(); function_output_iterator& operator++(int); private: UnaryFunction m_f; // exposition only }; function_output_iterator requirementsUnaryFunctionдолжна быть уступчивой и копируемой. function_output_iterator modelsfunction_output_iteratorявляется моделью концепций Writable and Incrementable Iterator. function_output_iterator operationsявнаяфункция_output_iterator(constUnaryFunction&f=UnaryFunction());
оператор*();
function_output_iterator&operator++();
function_output_iterator&operator++(int);
Статья Iterator Facade and Adaptor раздела может быть полезна для разработчиков на c++ и boost. Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта. :: Главная :: ::
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
©KANSoftWare (разработка программного обеспечения, создание программ, создание интерактивных сайтов), 2007 |