Spec-Zone.ru › C++

std::input_iterator_tag, std::output_iterator_tag, std::forward_iterator_tag, std::bidirectional_iterator_tag, std::random_access_iterator_tag, std::contiguous_iterator_tag

Определено в заголовке <iterator>
struct input_iterator_tag {};
(1)
struct output_iterator_tag {};
(2)
struct forward_iterator_tag : public input_iterator_tag {};
(3)
struct bidirectional_iterator_tag : public forward_iterator_tag {};
(4)
struct random_access_iterator_tag : public bidirectional_iterator_tag {};
(5)
struct contiguous_iterator_tag : public random_access_iterator_tag {};
(6) (с C++20)

Определяет категорию итератора. Каждый тег представляет собой пустой тип.

Категория итератора

Для каждого типа LegacyIterator It, должен быть определён typedef std::iterator_traits<It>::iterator_category как псевдоним одного из этих типов тегов, чтобы указать наиболее конкретную категорию, к которой относится It.

  1. input_iterator_tag соответствует LegacyInputIterator.
  2. output_iterator_tag соответствует LegacyOutputIterator.
  3. forward_iterator_tag соответствует LegacyForwardIterator.
  4. bidirectional_iterator_tag соответствует LegacyBidirectionalIterator.
  5. random_access_iterator_tag соответствует LegacyRandomAccessIterator.

Теги категорий итераторов несут информацию, которая может использоваться для выбора наиболее эффективных алгоритмов для конкретного набора требований, подразумеваемого категорией.

Концепция итератора

Для каждого типа input_iterator It, может быть объявлен либо It::iterator_concept (если std::iterator_traits<It> сгенерирован из первичной шаблонной функции) либо std::iterator_traits<It>::iterator_concept (если std::iterator_traits<It> специализирован), как псевдоним одного из этих тегов, чтобы указать самую сильную концепцию итератора, которую It намеревается моделировать.

  1. input_iterator_tag соответствует input_iterator.
  2. forward_iterator_tag соответствует forward_iterator.
  3. bidirectional_iterator_tag соответствует bidirectional_iterator.
  4. random_access_iterator_tag соответствует random_access_iterator.
  5. contiguous_iterator_tag соответствует contiguous_iterator.

Если iterator_concept не предоставлен, iterator_category используется как резервный вариант. Если iterator_category также не предоставлен (т. е. It не является LegacyIterator), и std::iterator_traits<It> не специализирован, используется random_access_iterator_tag.

В любом случае, каждая концепция не удовлетворяется, если необходимые операции не поддерживаются, независимо от тега.

(с C++20)

Примечания

Нет отдельного тега для LegacyContiguousIterator. То есть, невозможно определить LegacyContiguousIterator на основе его iterator_category. Для определения специализированного алгоритма для смежных итераторов используйте концепцию contiguous_iterator.(с C++20)

Нет соответствия между output_iterator_tag и концепцией output_iterator. Установка iterator_concept в output_iterator_tag указывает только на то, что тип не моделирует input_iterator.

Пример

Распространённый метод выбора алгоритма на основе тегов категорий итераторов — использование функции диспетчера (альтернатива — std::enable_if). Классы тегов итераторов также используются в определениях соответствующих концепций для обозначения требований, которые нельзя выразить только через схемы использования.(с C++20)

#include <iostream>
#include <iterator>
#include <list>
#include <vector>
 
// Using concepts (tag checking is part of the concepts themselves)
 
template<std::bidirectional_iterator BDIter>
void alg(BDIter, BDIter)
{
    std::cout << "1. alg() \t called for bidirectional iterator\n";
}
 
template<std::random_access_iterator RAIter>
void alg(RAIter, RAIter)
{
    std::cout << "2. alg() \t called for random-access iterator\n";
}
 
// Legacy, using tag dispatch
 
namespace legacy
{
    // Quite often implementation details are hidden in a dedicated namespace
    namespace implementation_details
    {
        template<class BDIter>
        void alg(BDIter, BDIter, std::bidirectional_iterator_tag)
        {
            std::cout << "3. legacy::alg() called for bidirectional iterator\n";
        }
 
        template<class RAIter>
        void alg(RAIter, RAIter, std::random_access_iterator_tag)
        {
            std::cout << "4. legacy::alg() called for random-access iterator\n";
        }
    } // namespace implementation_details
 
    template<class Iter>
    void alg(Iter first, Iter last)
    {
        implementation_details::alg(first, last,
            typename std::iterator_traits<Iter>::iterator_category());
    }
} // namespace legacy
 
int main()
{
    std::list<int> l;
    alg(l.begin(), l.end()); // 1.
    legacy::alg(l.begin(), l.end()); // 3.
 
    std::vector<int> v;
    alg(v.begin(), v.end()); // 2.
    legacy::alg(v.begin(), v.end()); // 4.
 
//  std::istreambuf_iterator<char> i1(std::cin), i2;
//  alg(i1, i2);         // compile error: no matching function for call
//  legacy::alg(i1, i2); // compile error: no matching function for call
}

Вывод:

1. alg()          called for bidirectional iterator
3. legacy::alg() called for bidirectional iterator
2. alg()          called for random-access iterator
4. legacy::alg() called for random-access iterator

См. также

iterator
(устаревший в C++17)
базовый класс для облегчения определения требуемых типов для простых итераторов
(шаблон класса)
iterator_traits
обеспечивает единообразный интерфейс к свойствам итератора
(шаблон класса)

© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/w/cpp/iterator/iterator_tags

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API