![]() |
![]() ![]() ![]() ![]() ![]() |
![]() |
New Iterator ConceptsBoost , ,
|
Author: | Дэвид Абрахамс, Джереми Сик, Томас Витт |
---|---|
Contact: | Авторские права Дэвид Абрахамс, Джереми Сик и Томас Витт 2003. |
Abstract: | We propose a new system of iterator concepts that treat access and positioning independently. This allows the concepts to more closely match the requirements of algorithms and provides better categorizations of iterators that are used in practice. |
---|
Table of Contents
Стандартные категории и требования итератора имеют недостатки, поскольку они используют одну иерархию понятий для решения двух ортогональных вопросов: прохождение итератора и доступ к значению . В результате многие алгоритмы с требованиями, выраженными в категориях итераторов, слишком строги. Кроме того, многие реальные итераторы не могут быть точно классифицированы. Например, прокси-итератор со случайным доступом может юридически иметь только категорию "входной итератор", поэтому общие алгоритмы не могут воспользоваться его возможностями случайного доступа. Нынешняя иерархия концепции итератора ориентирована на обход итератора (отсюда названия категорий), в то время как требования, касающиеся доступа к стоимости, проникают в различные места. В следующей таблице приводится краткое изложение текущих требований к доступу к стоимости в категориях итераторов.
Value Access Requirements in Existing Iterator Categories | |
---|---|
Производитель Iterator | *i = a |
Итератор ввода | *i можно конвертировать в T |
Передний итератор | *i T& (или const T& после разрешения выпуска 200) |
Итератор случайного доступа | i[n] преобразуется в T (также i[n]=t требуется для итераторов с изменяемостью после разрешения вопрос 299) |
Поскольку обход итератора и доступ к стоимости смешиваются в одной иерархии, многие полезные итераторы не могут быть соответствующим образом классифицированы. Например, vector
Другим сложным для категоризации итератором является преобразующий итератор, адаптер, который применяет объект унарной функции к отнесенному значению некоторого базового итератора (см. transform_iterator). Для унарных функций, таких как times, тип возврата оператора* явно должен быть result_type объекта функции, который обычно не является ссылкой. Поскольку итераторы случайного доступа должны возвращать значения l от оператора*, если вы обернете int* с помощью итератора преобразования, вы получите итератор случайного доступа не так, как можно было бы ожидать, а итератор ввода.
Третий пример можно найти в итераторах вершины и края библиотеки Boost Graph Library. Эти итераторы возвращают дескрипторы вершины и края, которые являются легкими ручками, созданными на лету. Они должны быть возвращены по стоимости. В результате их текущая стандартная категория итераторов - input_iterator_tag, что означает, что, строго говоря, вы не можете использовать эти итераторы с такими алгоритмами, как min_element(). В качестве временного решения была введена концепция Multi-Pass Input Iterator для описания дескрипторов вершины и края, но, как показывают примечания к концепции, требуется лучшее решение.
Короче говоря, есть много полезных итераторов, которые не вписываются в текущие стандартные категории итераторов. В результате происходят следующие плохие вещи:
Это предложение для TR1 является чистым расширением. Кроме того, новые концепции итератора обратно совместимы со старыми требованиями итератора, а старые итераторы - с новыми концепциями итератора. Другими словами, итераторы, удовлетворяющие старым требованиям, также удовлетворяют соответствующим концепциям в новой системе, и итераторы, моделирующие новые концепции, автоматически удовлетворяют соответствующим старым требованиям.
Расширения в этом документе предлагают несколько изменений, которые мы можем внести в рабочий документ для следующего стандарта. Эти изменения не являются формальной частью этого предложения по TR1.
Алгоритмы в стандартной библиотеке могут извлечь выгоду из новых концепций итераторов, поскольку новые концепции обеспечивают более точный способ выражения требований к типу. В результате алгоритмы могут использоваться в большем количестве ситуаций и имеют меньше требований к типу.
Для следующего рабочего документа (но не для TR1) комитет должен рассмотреть следующие изменения в требованиях к типу алгоритмов. Эти изменения сформулированы как текстовые замены, перечисляя алгоритмы, к которым применяется каждая текстовая замена.
Передний итератор (Forward Traversal Iterator and Readable Iterator)
find_end, adjacent_find, search, search_n, rotate_copy, lower_bound, upper_bound, equal_range, binary_search, min_element, max_element
Передний итератор (1) -> Single Pass Iterator и Readable Iterator, Forward Iterator (2) -> Forward Traversal Iterator и Readable Iterator
find_first_of
Передний итератор - > читаемый итератор и письменный итератор
iter_swap
Forward Iterator - > Итератор с одним проходом и письменный итератор
fill, generate
Форвардный итератор (Forward Traversal Iterator and Swappable Iterator)
rotate
Передний итератор (1) -> Swappable Iterator и Single Pass Iterator, Forward Iterator (2) -> Swappable Iterator и Incrementable Iterator
swap_ranges
Forward Iterator -> Single Pass Iterator и Readable Iterator
replace, replace_if
Двунаправленный итератор (1) -> двунаправленный итератор поворота и читаемый итератор, двунаправленный итератор (2) -> двунаправленный итератор поворота и письменный итератор
copy_backwards
Для следующего рабочего документа (но не для TR1) комитету следует рассмотреть возможность обесценивания старых тегов итератора и std::iterator_traits, поскольку он будет заменен отдельными метафункциями признаков.
Для следующего рабочего документа (но не для TR1) комитету следует рассмотреть возможность реклассификации vector
Требования к итератору должны быть разделены на две группы. Один набор понятий обрабатывает синтаксис и семантику доступа к стоимости:
Концепции доступа описывают требования, относящиеся к оператору* и оператору->, включая значение_тип, ссылка и поисковик ассоциированных типов.
Другой набор понятий обрабатывает прохождение:
Соотношения уточнения для концепций прохождения находятся на следующей диаграмме.
В дополнение к операторам движения итератора, таким как оператор++, концепции обхода также включают требования к сравнению позиций, такие как оператор== и оператор<. Причина тонкого срезания концептов в Инкрементируемый и Единый проход состоит в том, чтобы предоставить концепции, которые точно соответствуют первоначальным требованиям итератора ввода и вывода.
Это предложение также включает в себя концепцию для определения, когда итератор совместим с другим итератором, в том смысле, что int* совместим с intconst*.
Связь между понятиями нового итератора и старого приведена на следующей диаграмме.
Как и в случае со старыми требованиями к итератору, мы предоставляем теги для отправки, основанные на концепциях обхода. Теги связаны через наследование, так что тег конвертируется в другой тег, если концепция, связанная с первым тегом, является уточнением второго тега.
Наш дизайн повторно использует iterator_traits
Мы не предоставляем теги для отправки на основе концепций доступа, отчасти потому, что мы не смогли найти способ автоматически вывести правильные теги доступа для итераторов старого стиля. Письменность итератора может зависеть от возможности присваивания его value_type и нет известного способа определить, можно ли назначить произвольный тип. К счастью, потребность в диспетчеризации на основе возможностей доступа не так велика, как потребность в диспетчеризации на основе возможностей прохождения.
Сложное дизайнерское решение касалось оператора . Прямой подход для определения оператор [] будет иметь тип возврата ссылка ; такой же, как оператор*. Однако движение в этом направлении будет означать, что итератор, удовлетворяющий старым требованиям Random Access Iterator, не обязательно будет моделью Readable или Writable Lvalue Iterator. Вместо этого мы выбрали дизайн, который соответствует предпочтительному разрешению , выпуск 299: оператор [] требуется только для возврата чего-либо конвертируемого в value_type (для Readable Iterator), и требуется поддержка назначения i[n] t (для Writable Iterator).
В таблицах ниже X является типом итератора, a является постоянным объектом типа R является std::iterator_traits
Класс или встроенный тип X моделирует концепцию Readable Iterator для типа значения T, если, помимо того, что X является Подлежащим и Копируемым, следующие выражения являются действительными и уважают заявленную семантику. U - тип любого указанного элемента типа T.
Readable Iterator Requirements (in addition to Assignable and Copy Constructible) | ||
---|---|---|
Expression | Return Type | Note/Precondition |
iterator_traits |
T | Любой нессылочный, не-cv-квалифицированный тип |
*a | Преобразуется в T |
|
a>m | U& | pre: pre: (*a.m четко определен. Эквивалент (*a.m. |
Класс или встроенный тип X моделирует концепцию Письменный итератор, если в дополнение к X Конструктивные, следующие выражения действительны и уважают заявленную семантику. Записываемые итераторы имеют ассоциированный набор типов значений .
Writable Iterator Requirements (in addition to Copy Constructible) | ||
---|---|---|
Expression | Return Type | Precondition |
*a=o | pre: Тип o находится в наборе типов значений X |
Класс или встроенный тип X моделирует концепцию Swappable Iterator, если в дополнение к X Конструктивные, следующие выражения действительны и уважают заявленную семантику.
Swappable Iterator Requirements (in addition to Copy Constructible) | ||
---|---|---|
Expression | Return Type | Postcondition |
iter_swap(a, b) | void | указанные значения обмениваются |
[Примечание: Итератор, являющийся моделью концепций Readable Iterator и Writable Iterator, также является моделью Swappable Iterator. - конец примечания
Концепция Lvalue Iterator добавляет требование, чтобы тип возврата operator* был ссылкой на тип значения итератора.
Lvalue Iterator Requirements | ||
---|---|---|
Expression | Return Type | Note/Assertion |
*a | T& | T - cv iterator_traits |
Если X является Письменный итератор, то a==b если и только если *a является тем же объектом, что и *b. Если X является Readable Iterator, то a==b подразумевает *a тот же объект, что и *b.
В приведенных ниже таблицах X является типом итератора, a являются постоянными объектами типа X, r и s являются изменчивыми объектами типа X, T является std::iterator_traits
Класс или встроенный тип X моделирует концепцию Incrementable Iterator, если, помимо того, что X является приемлемым и конструируемым для копирования, следующие выражения являются действительными и уважают заявленную семантику.
Incrementable Iterator Requirements (in addition to Assignable, Copy Constructible) | ||
---|---|---|
Expression | Return Type | Assertion |
++r | X& | &r == &++r |
r++ | ||
*r++ | ||
iterator_traversal |
Преобразуемый в incrementable_traversal_tag |
Если X является Письменный итератор, то X a(r++); эквивалентен X ++r;r++oo;++r. Если X является Readable Iterator, то T z(*r++); эквивалентно T z(*r); ++r;.
Класс или встроенный тип X моделирует концепцию Single Pass Iterator, если следующие выражения действительны и уважают заявленную семантику.
Single Pass Iterator Requirements (in addition to Incrementable Iterator and Equality Comparable) | |||
---|---|---|---|
Expression | Return Type | Operational Semantics | Assertion/ Pre-/Post-condition |
++r | X& | pre: r является сносным; post: r является сносным или r является прошедшим-концом | |
a==b | конвертируемый в bool | == является отношением эквивалентности по своей области | |
a!=b | конвертируемый в bool | !(a == b) | |
iterator_traits |
Знаковый интегральный тип, представляющий расстояние между итераторами | ||
iterator_traversal |
Преобразуемый в single_pass_traversal_tag |
Класс или встроенный тип X моделирует концепцию Forward Traversal Iterator, если, помимо X, удовлетворяет требованиям Default Constructible и Single Pass Iterator, следующие выражения действительны и уважают заявленную семантику.
Forward Traversal Iterator Requirements (in addition to Default Constructible and Single Pass Iterator) | ||
---|---|---|
Expression | Return Type | Assertion/Note |
Xu; | X& | примечание: u может иметь единственное значение. |
++r | X& | r == и r является допустимым ++r == ++s. |
iterator_traversal |
Преобразуемый в forward_traversal_tag |
Класс или встроенный тип X моделирует концепцию Bidirectional Traversal Iterator, если в дополнение к X удовлетворяют требованиям Forward Traversal Iterator, следующие выражения являются действительными и уважают заявленную семантику.
Bidirectional Traversal Iterator Requirements (in addition to Forward Traversal Iterator) | |||
---|---|---|---|
Expression | Return Type | Operational Semantics | Assertion/ Pre-/Post-condition |
-r | X& | предыдущее: существует s так, что r == ++s. пост: s является сносным. ++(--r) == r. -r == -s подразумевает r ==. &r == &-r. |
|
r-- | конвертируемый в const X& | { X tmp = r; -r; возврат tmp; } |
|
iterator_traversal |
Преобразуемый в bidirectional_traversal_tag |
Класс или встроенный тип X моделирует концепцию Random Access Traversal Iterator, если следующие выражения действительны и уважают заявленную семантику. В таблице ниже Distance является iterator_traits
Random Access Traversal Iterator Requirements (in addition to Bidirectional Traversal Iterator) | |||
---|---|---|---|
Expression | Return Type | Operational Semantics | Assertion/ Precondition |
r += n | X& | { Расстояние m = n; если (m >= 0) в то время как (m--) ++r; в то время как (m++) -r; возврат r; } |
|
an, n | X | { tmp = a; возврат tmp n; <21 | |
r -= n | X& | возврат r += -n | |
a-n | X | { tmp = a; возврат tmp n; | |
b-a | Расстояние | ab? distance(a,b):-distance(b,a) | pre: существует значение n Расстояние, такое, что a + n ==b. b==a+(b-a). |
a[n] | конвертируемый в T | *(a + n) | pre: a - Readable Iterator |
a[n]=v | конвертируемый в T | *(a + n) = v | pre: a - Письменный итератор |
a<b | конвертируемый в bool | b-a>0<11 | < является отношением полного упорядочения |
a > b | конвертируемый в bool | b<a | > является отношением полного упорядочения |
a >= b | конвертируемый в bool | !(a < b) | |
a<=b | конвертируемый в bool | !(a > b) | |
iterator_traversal |
Преобразуемый в random_access_traversal_tag |
Класс или встроенный тип X Single Pass Iterator совместим с классом или встроенным типом Y, который также моделируется Итератор с одним проходом, если следующие выражения действительны и уважают заявленную семантику. В таблицах ниже x является объектом типа X, y является объектом типа Y, Distance является iterator_traits
Expression | Return Type | Assertion/Precondition/Postcondition |
---|---|---|
y = x | Y | y == x |
Y(x) | Y | post: Y(x) == x |
x ==y | конвертируемый в bool | == является отношением эквивалентности по своей области. |
y == x | конвертируемый в bool | == является отношением эквивалентности по своей области. |
x!=y | конвертируемый в bool | bool(a==b) != bool(a!=b) над его доменом. |
y != x | конвертируемый в bool | bool(a==b) != bool(a!=b) над его доменом. |
Если X и Y обе модели Random Access Traversal Iterator, то необходимо выполнить следующие дополнительные требования.
Expression | Return Type | Operational Semantics | Assertion/ Precondition |
---|---|---|---|
x<y | конвертируемый в bool | y - x > 0<11 | < является отношением полного упорядочения |
y < x | конвертируемый в bool | x-y>0<11 | < является отношением полного упорядочения |
x > y | конвертируемый в bool | y < x | > является отношением полного упорядочения |
y > x | конвертируемый в bool | x<y | > является отношением полного упорядочения |
x >= y | конвертируемый в bool | !(x < y>2> | |
y >= x | конвертируемый в bool | !(y < x) | |
x <=y | конвертируемый в bool | !(x > y>2> | |
y <= x | конвертируемый в bool | !(y > x) | |
y - x | Расстояние | расстояние(Y(x),y) | pre: существует значение n Расстояние, такое, что x + n ==y. y == x + (y-x). |
x-y | Расстояние | расстояние(y,Y(x)) | pre: существует значение n Расстояние, такое, что y + n == x. x==y+(x-y). |
// lib.iterator.traits, traits and tags template <class Iterator> struct is_readable_iterator; template <class Iterator> struct iterator_traversal; struct incrementable_traversal_tag { }; struct single_pass_traversal_tag : incrementable_traversal_tag { }; struct forward_traversal_tag : single_pass_traversal_tag { }; struct bidirectional_traversal_tag : forward_traversal_tag { }; struct random_access_traversal_tag : bidirectional_traversal_tag { };
Шаблон класса is_readable_iterator удовлетворяет требованиям UnaryTypeTrait.
Учитывая тип итератора X, is_readable_iterator
iterator_traversal
category-to-traversal(iterator_traits<X>::iterator_category)
где категория-переход определяется следующим образом:
category-to-traversal(C) = if (C is convertible to incrementable_traversal_tag) return C; else if (C is convertible to random_access_iterator_tag) return random_access_traversal_tag; else if (C is convertible to bidirectional_iterator_tag) return bidirectional_traversal_tag; else if (C is convertible to forward_iterator_tag) return forward_traversal_tag; else if (C is convertible to input_iterator_tag) return single_pass_traversal_tag; else if (C is convertible to output_iterator_tag) return incrementable_traversal_tag; else the program is ill-formed
Статья New Iterator Concepts раздела может быть полезна для разработчиков на c++ и boost.
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.
:: Главная :: ::
реклама |