Как работает категория итератора в C++?

Я попытался понять реализацию итератора, и, играя с источником, я увидел следующее утверждение:

typedef output_iterator_tag iterator_category;

Я не понимаю, как этот typedef работает в классе? Какой побочный эффект это дает? Кто-нибудь может провести меня через это?

2 ответов


вам нужно почитать об обобщенном программировании, потому что вы вряд ли получите ответ.

"выходной итератор" - это концепция, которая соответствует определенным итераторам. Каждый итератор, который является реализацией этой концепции, имеет определенную функциональность, связанную с ней. Это что-то вроде наследства, но это не так.--2-->

C++ не имеет ничего такого, что представляет концепции (было предложено дополнение к C++0x, но не удалось сделать это). В этом случае нам нужны различные конструкции шаблонов позволяют связать " тег " с типом итератора. Связывая тип output_iterator_tag с итератором, мы утверждаем, что наш тип итератора реализует концепцию OutputIterator.

это становится очень важным, когда вы пытаетесь написать алгоритмы, которые максимально оптимизированы, а также универсальные. Например, выполнение сортировки с итератором, который может быть увеличен или уменьшен на произвольное значение (кроме 1, другими словами) больше эффективнее, чем тот, у которого нет такой возможности. Кроме того, для получения нового итератора, который находится на расстоянии X от другого, могут потребоваться различные операции в зависимости от возможностей итератора. Для написания такого алгоритма используется "диспетчеризация тегов". Чтобы объяснить это более полно, вот реализация (непроверенная) std:: advance, которая работает как с итераторами, имеющими оператор+=, так и с теми, у которых есть только оператор++, и как можно быстрее с обоими версии.

template < typename RandomAccessIterator >
RandomAccessIterator advance( RandomAccessIterator it
                            , int amount
                            , random_access_iterator_tag) 
{ return it + amount; }

template < typename ForwardIterator >
ForwardIterator advance(ForwardIterator it, int amount, forward_iterator_tag)
{
  for (;amount; --amount) ++it;
  return it;
}

template < typename Iterator >
Iterator advance(Iterator it, int amount)
{
  typedef typename std::iterator_traits<Iterator>::iterator_tag tag;
  advance(it, amount, tag());
}

Это из памяти, поэтому он, вероятно, пронизан ошибками (возможно, даже есть куча типов)...но это идея. Теги итератора-это пустые типы, которые также наследуются друг от друга точно так же, как понятия уточняют друг друга. Например, итератор произвольного доступа-это прямой итератор. Таким образом, random_access_iterator_tag является производной от forward_iterator_tag. Из-за правил разрешения перегрузки функции передавая random_access_iterator_tag для функции разрешает эту версию функции, а не forward_iterator_tag.

опять же, перейдите к общему программированию. Важно использовать всю мощь c++.

Ну, и напоследок... Typedef есть в определении класса итератора, потому что это хорошее, удобное место для его размещения. По умолчанию iterator_traits может искать его там. Вы захотите использовать iterator_traits вместо этого определения хотя, потому что необработанные указатели тоже являются итераторами, и у них не может быть внутренних typedefs.


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

например, в заголовке VS2010 алгоритм "std::distance"имеет две реализации в зависимости от типа "iterator_category" в переданных итераторах.

std:: distance требует только входного итератора для вычисления расстояния между двумя итераторами, но для вычисления ответа может потребоваться линейное время " O(n)".

Если, однако, компилятор выясняет, что используется итератор произвольного доступа, и поэтому может использовать оператор вычитания для вычисления расстояния в постоянное время " O(1)".

Я бы рекомендовал смотреть Стефана т. Лававея видео куда он идет разбиение на признаки типа и их использование в стандартной библиотеке шаблонов.