Карта сайта Kansoftware
НОВОСТИУСЛУГИРЕШЕНИЯКОНТАКТЫ
Разработка программного обеспечения

Improved Iterator Categories and Requirements

Boost , ,

Boost C++ Libraries

...one of the most highly regarded and expertly designed C++ library projects in the world. Herb Sutter and Andrei Alexandrescu, C++ Coding Standards

Document number:

J16/01-0011 = WG21 N1297

Date:

21 марта 2001 года

Author:

Джереми Сик,
Университет Нотр-Дам

jsiek@lsc.nd.edu

Improved Iterator Categories and Requirements

Introduction

The standard iterator categories and requirements are flawed because they use a single hierarchy of requirements to address two orthogonal issues: iterator traversal and dereference return type. The current iterator requirement hierarchy is mainly geared towards iterator traversal (hence the category names), while requirements that address dereference return type sneak in at various places. The following table gives a summary of the current dereference return type requirements in the iterator categories.

Table 1. Summary of current dereference return type requirements.
Производитель Iterator *i = a
Итератор ввода *iконвертируется вT
Передний итератор *i-T&(илиconst T&после решениявопроса 200
Итератор случайного доступа i[n]конвертируется вT(что странно, потому что операционная семантика говоритi [n]эквивалентна* (i + n), который будет иметь тип возврата). T&

Examples of useful iterators that do not ``fit''

Из-за смешивания итератора и типа возврата отсчета многие полезные итераторы не могут быть соответствующим образом классифицированы. Например,vector::iteratorявляется почти итератором случайного доступа, но тип возврата неbool&(см.выпуск 96и статью Херба Саттера J16/99-0008 = WG21 N1185). Поэтому итераторы отвечают только требованиям входного итератора и выходного итератора. Это настолько нелогично, что по меньшей мере одна реализация ошибочно присваиваетrandom_access_iterator_tagв качестве егоiterator_category. Кроме того,vector— не единственный пример полезных итераторов, которые не возвращают истинных ссылок: есть часто приводимый пример дисковых коллекций.

Другой пример — итератор подсчета, итератор возвращает последовательность целых чисел при инкрементировании и отсчете (см.boost::counting_iterator). Существует два способа реализации этого итератора: 1) сделатьэталонныйтип истинной ссылкой (ссылка на целый элемент данных счетного итератора) или 2) сделатьэталонныйтип таким же, какзначение_тип. Вариант 1) сталкивается с проблемами, обсуждаемыми вВыпуске 198, ссылка не будет действительна после уничтожения итератора. Поэтому вариант 2) является лучшим выбором, но тогда у нас есть счетчик итератора, который не может быть итератором случайного доступа.

Еще одним примером является преобразующий итератор, адаптер итератора, который применяет объект унарной функции к сносному значению обернутого итератора (см.boost::transform_iterator). Для унарных функций, таких какstd::times, тип возврата оператора*явно должен бытьresult_typeобъекта функции, который обычно не является ссылкой. Однако при нынешних требованиях к итератору, если вы завернетеint*с преобразователем, вы получите не итератор случайного доступа, как ожидалось, а итератор ввода.

Четвертый пример можно найти в итераторах вершины и края библиотекиBoost Graph Library. Эти итераторы возвращают дескрипторы вершины и края, которые являются легкими ручками, созданными на лету. Они должны быть возвращены по стоимости. В результате их текущей стандартной категорией итераторов являетсяstd::input_iterator_tag, что означает, что, строго говоря, вы не можете использовать эти итераторы с такими алгоритмами, какstd::min_element().. В качестве временного решения мы представили концепциюMulti-Pass Input Iteratorдля описания дескрипторов вершины и края, но, как показывают примечания к концепции, требуется лучшее решение.

Короче говоря, есть много полезных итераторов, которые не вписываются в текущие стандартные категории итераторов. В результате происходят следующие плохие вещи:

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

Proposal for new iterator categories and requirements

The iterator requirements should be separated into two hierarchies. One set of concepts handles the return type semantics: The other set of concepts handles iterator traversal: The current Input Iterator and Output Iterator requirements will continue to be used as is. Note that Input Iterator implies Readable Iterator and Output Iterator implies Writable Iterator.

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

New categories and traits classes

Each of the new iterator requirements will need a category tag.
namespace std {
  // Return Type Categories
  struct readable_iterator_tag { };
  struct writable_iterator_tag { };
  struct swappable_iterator_tag { };
  struct mutable_lvalue_iterator_tag : virtual public writable_iterator_tag,
    virtual public readable_iterator_tag { };
  struct constant_lvalue_iterator_tag : public readable_iterator_tag { };
  // Traversal Categories
  struct forward_traversal_tag { };
  struct bidirectional_traversal_tag : public forward_traversal_tag { };
  struct random_access_traversal_tag : public bidirectional_traversal_tag { };
}
And there will need to be a way to access these category tags using a traits mechanism. Adding new typedefs to std::iterator_traits is not an acceptable solution because that would break every existing iterator. Instead, we propose two new traits classes. It is important that these traits classes are backward compatible, that is, they should work with any iterator for which there is a valid definition of std::iterator_traits. This can be accomplished by making the default behavior of the traits classes map the iterator_category of the iterator to the appropriate return or traversal category. For new iterators, either specializations of these traits classes can be defined, or the iterator can provide nested typedefs, and inherit from new_iterator_base (which is just a signal to the traits class that it is a new iterator). As with std::iterator_traits, specializations for T* are provided.
namespace std {
  struct new_iterator_base { };
  template <typename Iterator>
  struct return_category
  {
    // Pseudo-code
    if (Iterator inherits from new_iterator_base) {
      typedef typename Iterator::return_category type;
    } else {
      typedef std::iterator_traits<Iterator> OldTraits;
      typedef typename OldTraits::iterator_category Cat;
      if (Cat inherits from std::forward_iterator_tag)
	if (is-const(T))
	  typedef boost::constant_lvalue_iterator_tag type;
	else
	  typedef boost::mutable_lvalue_iterator_tag type;
      else if (Cat inherits from std::input_iterator_tag)
	typedef boost::readable_iterator_tag type;
      else if (Cat inherits from std::output_iterator_tag)
	typedef boost::writable_iterator_tag type;
    }
  };
  template <typename T>
  struct return_category<T*>
  {
    // Pseudo-code
    if (is-const(T))
      typedef boost::constant_lvalue_iterator_tag type;
    else
      typedef boost::mutable_lvalue_iterator_tag type;
  };
  template <typename Iterator>
  struct traversal_category
  {
    // Pseudo-code
    if (Iterator inherits from new_iterator_base) {
      typedef typename Iterator::traversal_category type;
    } else {
      typedef std::iterator_traits<Iterator> OldTraits;
      typedef typename OldTraits::iterator_category Cat;
      if (Cat inherits from std::random_access_iterator_tag)
	typedef boost::random_access_traversal_tag type;
      else if (Cat inherits from std::bidirectional_iterator_tag)
	typedef boost::bidirectional_traversal_tag type;
      else if (Cat inherits from std::forward_iterator_tag)
	typedef boost::forward_traversal_tag type;
    }
  };
  template <typename T>
  struct traversal_category<T*>
  {
    typedef boost::random_access_traversal_tag type;
  };
}

Impact on the Standard Algorithms

Many of the standard algorithms place more requirements than necessary on their iterator parameters due to the coarseness of the current iterator categories. By using the new iterator categories a better fit can be achieved, thereby increasing the reusability of the algorithms. These changes will not affect user-code, though they will require changes by standard implementers: dispatching should be based on the new categories, and in places return values may need to be handled more carefully. In particular, uses of std::swap() will need to be replaced with std::iter_swap(), and std::iter_swap() will need to call std::swap().

Table 2. Requirement changes for standard algorithms.
Algorithm Requirement Change
find_end Передний итератор
-> Forward Traversal Iterator and Readable Iterator
Find_first_of
Обсуждение Next_find
поиск
Search_n
ротация_копия
Нижний ->>
верхний
равный
binary_search
мин_элемент
max_element
iter_swap Передний итератор
-> Swappable Iterator
заполнять Передний итератор
-> Forward Traversal Iterator and Writable Iterator
генерировать
swap_ranges Передний итератор
-> Forward Traversal Iterator and Swappable Iterator
вращать
заменить Передний итератор
-> Forward Traversal Iterator and
Readable Iterator and Writable Iterator
Заменить
удалять
Удалить ___
уникальный
обратный Bidirectional Iterator
-> Bidirectional Traversal Iterator and Swappable Iterator
раздел
copy_backwards Двунаправленный итератор
->Двунаправленный итератор поворота и читаемый итератор
Двунаправленный итератор
->Двунаправленный итератор поворота и письменный итератор
Next_Пермутация Bidirectional Iterator
-> Bidirectional Traversal Iterator and
Swappable Iterator and Readable Iterator
prev_permutation
Стабильный_раздел Bidirectional Iterator
-> Bidirectional Traversal Iterator and
Readable Iterator and Writable Iterator
Вместо_merge
reverse_copy Двунаправленный итератор
->Двунаправленный итератор поворота и читаемый итератор
random_suffle Итератор случайного доступа
-> Random Access Traversal Iterator and Swappable Iterator
сортировать
stable_sort
part_sort
nth_элемент
push_ap
pop_ap
make_ap
сорт

The New Iterator Requirements

Notation

X Тип итератора.
Т Тип значенияX, т.е.std::iterator_traits::value_type.
x,y Объект типаX.
t Объект типаТ.


Readable Iterator

A Readable Iterator is an iterator that dereferences to produce an rvalue that is convertible to the value_type of the iterator.

Associated Types

Тип значения std::iterator_traits::value_type Тип объектов, на которые указывает итератор.
Тип ссылки std::iterator_traits::reference Тип возврата отсылки к итератору. Этот тип должен быть конвертируемым вТ.
Возвратная категория std::return_category::type Тип конвертируемого вstd::readable_iterator_tag

Refinement of

Copy Constructible

Valid expressions

Name Expression Type requirements Return type
Уважение *x   std::iterator_traits::reference
Доступ к члену x->m Tпредставляет собой тип с элементом, названнымm. Еслиmявляется членом данных, то типm. Еслиmявляется функцией члена, то возвращаемый типm.


Writable Iterator

A Writable Iterator is an iterator that can be used to store a value using the dereference-assignment expression.

Definitions

If x is an Writable Iterator of type X, then the expression *x = a; stores the value a into x. Note that operator=, like other C++ functions, may be overloaded; it may, in fact, even be a template function. In general, then, a may be any of several different types. A type A belongs to the set of value types of X if, for an object a of type A, *x = a; is well-defined and does not require performing any non-trivial conversions on a.

Associated Types

Возвратная категория std::return_category::type Тип конвертируемого вstd::writable_iterator_tag

Refinement of

Copy Constructible

Valid expressions

Name Expression Return type
Уважение *x = a неуточненный


Swappable Iterator

A Swappable Iterator is an iterator whose dereferenced values can be swapped.

Примечание: требования к Swappable Iterator зависят от проблем, связанных с решениемstd::swap(). Здесь мы предполагаем, что проблема будет решена, разрешив перегрузкуstd::swap()для определенных пользователем типов.

Примечание: Readable Iterator and Writable Iterator Combined подразумевает Swappable Iterator из-за полностью шаблонизированногоstd::swap(). Однако Swappable Iterator не подразумевает ни Readable Iterator, ни Writable Iterator.

Associated Types

Возвратная категория std::return_category::type Тип конвертируемого вstd::swappable_iterator_tag

Valid expressions

Of the two valid expressions listed below, only one OR the other is required. If std::iter_swap() is overloaded for X then std::swap() is not required. If std::iter_swap() is not overloaded for X then the default (fully templated) version is used, which will call std::swap() (this means changing the current requirements for std::iter_swap()).

Name Expression Return type
Iterator Swap std::iter_swap(x, y) void
Dereference and Swap std::swap(*x, *y) void


Constant Lvalue Iterator

A Constant Lvalue Iterator is an iterator that dereferences to produce a const reference to the pointed-to object, i.e., the associated reference type is const T&. Changing the value of or destroying an iterator that models Constant Lvalue Iterator does not invalidate pointers and references previously obtained from that iterator.

Refinement of

Readable Iterator

Associated Types

Тип указателя -->
Тип ссылки std::iterator_traits::reference Тип возврата отсылки итератора, который должен бытьconst T&.
std::iterator_traits::pointer Указатель на тип значения, который должен бытьconst T*.
Возвратная категория std::return_category::type Тип конвертируемого вstd::constant_lvalue_iterator_tag
Уважение
*x   std::iterator_traits::reference
Доступ к члену x->m Tпредставляет собой тип с элементом, названнымm.  
-->


Mutable Lvalue Iterator

A Mutable Lvalue Iterator is an iterator that dereferences to produce a reference to the pointed-to object. The associated reference type is T&. Changing the value of or destroying an iterator that models Mutable Lvalue Iterator does not invalidate pointers and references previously obtained from that iterator.

Refinement of

Readable Iterator, Writable Iterator, and Swappable Iterator.

Associated Types

Тип указателя -->
Тип ссылки std::iterator_traits::reference Тип возврата отсылки итератора, который должен бытьT&.
std::iterator_traits::pointer Указатель на тип значения, который являетсяT*.
Возвратная категория std::return_category::type Тип конвертируемого вstd::mutable_lvalue_iterator_tag
Уважение *x   std::iterator_traits::reference Доступ к члену x->m Tпредставляет собой тип с элементом, названнымm.   -->


Forward Traversal Iterator

The Forward Iterator is an iterator that can be incremented. Also, it is permissible to make multiple passes through the iterator's range.

Refinement of

Copy Constructible, Assignable, Default Constructible, and Equality Comparable

Associated types

Разностный тип std::iterator_traits::difference_type Знаковый интегральный тип, используемый для представления расстояний между итераторами, которые указывают на один и тот же диапазон.
Траверсная категория std::traversal_category::type Тип конвертируемого вstd::forward_traversal_tag

Valid expressions

Name Expression Type requirements Return type
Прирост ++i   X&
Постприрост i++   конвертируемый вconst X&


Bidirectional Traversal Iterator

An iterator that can be incremented and decremented.

Refinement of

Forward Traversal Iterator

Associated types

Траверсная категория std::traversal_category::type Тип конвертируемого вstd::bidirectional_traversal_tag

Valid expressions

Name Expression Type requirements Return type
Предварительное определение --i   X&
Постдекрет Я--   конвертируемый вconst X&


Random Access Traversal Iterator

An iterator that provides constant-time methods for moving forward and backward in arbitrary-sized steps.

Refinement of

Bidirectional Traversal Iterator and Less Than Comparable where < is a total ordering

Associated types

Траверсная категория std::traversal_category::type Тип конвертируемого вstd::random_access_traversal_tag

Valid expressions

Name Expression Type requirements Return type
Добавление итератора i += n   X&
Добавление итератора i + nилиn + i   X
Вычитание итератора i -= n   X&
Вычитание итератора i - n   X
Разница i - j   std::iterator_traits::difference_type
Оператор элемента i [n] Xтакже должна быть моделью. Читаемый итератор. std::iterator_traits::reference
Задание элементов i [n] = t Xтакже должна быть моделью. Итератор. неуточненный


Статья Improved Iterator Categories and Requirements раздела может быть полезна для разработчиков на c++ и boost.




Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.



:: Главная :: ::


реклама


©KANSoftWare (разработка программного обеспечения, создание программ, создание интерактивных сайтов), 2007
Top.Mail.Ru

Время компиляции файла: 2024-08-30 11:47:00
2025-07-05 10:53:26/0.0093729496002197/0