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/cpp/iterator/iterator_tags

Spec-Zone.ru

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