В рамках этого примера мы разместили простой алгоритм счета в интерфейсе однонаправленного итератора. Реализация итератора и диапазона данных зачастую включает в себя написание минимального объема стереотипного кода, что, с одной стороны, может слегка раздражать. С другой стороны, взглянув на цикл, который использует num_range
, мы понимаем, что это здорово, поскольку цикл выглядит
Обеспечиваем совместимость собственных итераторов с категориями итераторов STL
Какую бы структуру данных вы ни создали, для эффективного
Проблема заключается в том, что многие алгоритмы STL пытаются больше узнать об итераторах, с которыми должны работать. Разные memcpy
. Если мы копируем данные из списка или в него, то такой вызов сделать
Как это делается
В этом примере мы реализуем примитивный итератор, считающий числа, и используем его вместе с алгоритмом STL, с которым он изначально не будет компилироваться. Затем сделаем все, чтобы итератор стал совместим с STL.
1. Сначала, как обычно, включим некоторые заголовочные файлы:
#include
#include
2. Далее реализуем примитивный итератор для подсчета чисел, как было показано в предыдущем разделе. При переборе он генерирует обычные увеличивающиеся целые числа. Диапазон данных num_range
выступает в роли удобного донора
class num_iterator
{
int i;
public:
explicit num_iterator(int position = 0) : i{position} {}
int operator*() const { return i; }
num_iterator& operator++() {
++i;
return *this;
}
bool operator!=(const num_iterator &other) const {
return i != other.i;
}
bool operator==(const num_iterator &other) const {
return !(*this != other);
}
};
class num_range {
int a;
int b;
public:
num_range(int from, int to)
: a{from}, b{to}
{}
num_iterator begin() const { return num_iterator{a}; }
num_iterator end() const { return num_iterator{b}; }
};
3. Чтобы избавиться от префикса пространства имен std::
и поддерживать код читабельным, объявим об использовании пространства имен std
:
using namespace std;
4. Теперь просто создадим диапазон данных, содержащий числа от 100
до 109
. Обратите внимание: конечный итератор стоит в позиции 110
. Это значит, что 110
— 100
и заканчивается значением 109
):
int main()
{
num_range r {100, 110};
5. Теперь воспользуемся им для std::minmax_element
. Алгоритм возвращает объект типа std::pair
с двумя членами: итератором, указывающим на минимальное значение, и другим итератором, указывающим на максимальное значение. В нашем примере этими значениями будут 100
и 109
, поскольку именно с их помощью мы создавали диапазон данных:
auto [min_it, max_it] (minmax_element(begin(r), end(r)));
cout << *min_it << " - " << *max_it << '\n';
}