Итератор конца sentinel
Итератор конца sentinel (страж) - это специальный объект,
который обозначает конец диапазона, но при этом может
иметь тип, отличный от типа обычного итератора. В отличие
от классического итератора end, sentinel не обязан
указывать на какой-либо элемент и не поддерживает
разыменование. Его единственная задача - сравниваться
с итератором и сообщать, достигнут ли конец диапазона.
Это позволяет, например, итерироваться по потоку ввода
или по строке C-стиля до нулевого символа, не зная
заранее длину диапазона. Первый параметр алгоритмов
принимает обычный итератор, а второй - sentinel,
завершающий обход.
Синтаксис
// Классический итератор конца
container.end()
// Пользовательский sentinel
struct sentinel
{
friend bool operator==(const iterator& it, sentinel)
{
return it.is_end();
}
};
Пример
Давайте создадим простой sentinel, который завершает
обход вектора, когда значение элемента становится
равным 3:
#include <iostream>
#include <vector>
using namespace std;
struct Sentinel
{
int stop_value;
};
bool operator==(const vector<int>::iterator& it, const Sentinel& s)
{
return *it == s.stop_value;
}
bool operator!=(const vector<int>::iterator& it, const Sentinel& s)
{
return !(it == s);
}
int main()
{
vector<int> vec = {1, 2, 3, 4, 5};
Sentinel s{3};
for (auto it = vec.begin(); it != s; ++it)
{
cout << *it << " ";
}
cout << endl;
return 0;
}
Результат выполнения кода:
1 2
Пример
Давайте используем sentinel для чтения чисел из стандартного ввода до нуля, что демонстрирует независимость sentinel от типа итератора:
#include <iostream>
#include <iterator>
using namespace std;
struct ZeroSentinel
{
};
bool operator==(const istream_iterator<int>& it, ZeroSentinel)
{
return it == istream_iterator<int>() || *it == 0;
}
bool operator!=(const istream_iterator<int>& it, ZeroSentinel)
{
return !(it == ZeroSentinel());
}
int main()
{
istream_iterator<int> it(cin);
ZeroSentinel s;
while (it != s)
{
cout << *it << " ";
++it;
}
cout << endl;
return 0;
}
Если ввести 1 2 3 0, то результат
выполнения кода будет:
1 2 3