Страницы

Поиск по вопросам

Показаны сообщения с ярлыком итераторы. Показать все сообщения
Показаны сообщения с ярлыком итераторы. Показать все сообщения

пятница, 13 марта 2020 г.

Обвертка над итератором для преобразования типа

#cpp #stl #boost #итераторы


Есть два типа A и B, между объектами этих типов установлено соответствие. Есть набор
X значений типа А и итератор по этому набору. Необходимо с минимальными трудозатратами
на основе итератора X получить итератор по значениям типа B.

В общем по-простому говоря, есть контейнер типа A, из итератора А нужно получить
итератор B, потому что клиент принимает итераторы B.

Например:

typedef std::pair A;
typedef float                 B;

B A2B(const A & item) // соответствие между A и B
{
    return item.second;
}

std::vector X;
input_iterator bi = magic_iterator_wrapper(A2B, X.begin());


Чем может быть magic_iterator_wrapper?
    


Ответы

Ответ 1



Можно использовать boost::transform_iterator #include #include #include #include using A = std::pair; using B = float; float A2B(const A & item) { return item.second; } template auto make_transform_iterator(I i, F f) { return boost::transform_iterator{i, f}; } int main() { std::vector
v = {{0, 1}, {0, 20}}; auto first = make_transform_iterator(v.begin(), A2B); auto last = make_transform_iterator(v.end(), A2B); std::cout << std::accumulate(first, last, 0) << '\n'; } >>> То же на реальном компиляторе <<<

воскресенье, 8 марта 2020 г.

Итерация по элементам строки: вытащить элемент, который будет числом и длина которого будет больше 4х символов

#python #регулярные_выражения #итераторы


Добрый день. Подскажите, могу ли я итерироваться по элементам строки? Например есть
строка а = 'qqqq 12qw3 12 12345', отсюда необходимо вытащить элемент, который будет
числом и длина которого будет больше 4х символов. Возможно, стоит использовать модуль
re, но я не могу понять, как задать в нём условие выбора элемента по его длине.
    


Ответы

Ответ 1



Строка: In [56]: a = 'qqqq a987654xx321aa 12qw3 12 12345 zz 1234567' Если необходимо вернуть только первое число длина которого больше 4х символов: In [72]: re.search(r'\b(\d{5,})\b', a).group(0) Out[72]: '12345' Вариант не использующий RegEx: In [68]: [s for s in a.split() if s.isdecimal() and len(s) > 4][0] Out[68]: '12345' Если необходимо вернуть все числа длина которых больше 4х символов: In [57]: re.findall(r'\b(\d{5,})\b', a) Out[57]: ['12345', '1234567'] или так, если считать числом 987654 присутствующим в a987654xx321aa: In [58]: re.findall(r'(\d{5,})', a) Out[58]: ['987654', '12345', '1234567']

среда, 26 февраля 2020 г.

С чем связано определение равенства потоковых итераторов?

#cpp #итераторы #iterator


Почему 2 std::istream_iterator считаются одинаковыми, даже если они указывают на
разные элементы одного потока? С чем связано такое определение?

Two stream iterators are equal if both of them are end-of-stream iterators or both
of them refer to the same stream.
    


Ответы

Ответ 1



Потому что std::istream_iterator указыает либо на конец связанного потока, либо на EOF. Когда вы выплняете инкремент итератора, он считывает элемент при помощи operator>>, а operator*, в свою очередь, просто возвращает ранее прочитанный элемент. Таким образом, std::istream_iterator всегда указывает туда, куда "указывает" связанный поток: std::istringstream stream{"1 2 3 4 5"}; std::istream_iterator it1{stream}; std::istream_iterator it2 = it1; std::cout << *it1 << std::endl; // 1 int i = 0; stream >> i; // take 2 ++it2; // take 3 ++it1; // take 4 std::cout << *it1 << std::endl; // 4 Пример

Ответ 2



если они указывают на разные элементы одного потока? А такое возможно вообще? Поток как бы синглетон в плане состояния, istream_iterator не скользит по потоку, а просто удобная обертка, чтобы можно было использовать во всех остальных местах STL.

Ответ 3



В потоке нет разных элементов, istream_iterator всегда работают с текущим положением потока. Элемент, к которому получается доступ при разыменовании итератора, хранится в самом итераторе, а не где-то в потоке. Этим он радикально отличается от итераторов контейнеров.

вторник, 28 января 2020 г.

Не могу понять пример с итератором

#stl #итераторы #cpp


#include 
#include 
#include 
#include 

int main()
{
    std::vector v;
    std::generate_n(std::back_insert_iterator>(v), // can be simplified
                    10, [](){ return std::rand() % 10; });        // with std::back_inserter
    for (int n : v)
        std::cout << n << ' ';
    std::cout << '\n';
}

А точнее эту строчку :
std::back_insert_iterator>(v), // can be simplified
                        10, [](){ return std::rand() % 10; }

и эту  :
    int n : v
Так вот в первом вообще какой-то бред в виде реализации функции в вызове другой функции.
А во втором явно не деление и на тернарный оператор не похоже.
Так что это?
Взял отсюда link    


Ответы

Ответ 1



То, что вам непонятно, появилось отностельно недавно в стандарте C++11 "реализация функции в вызове другой функции" есть не что иное как лямбда-функция - особая форма записи анонимной функции. И нет, это не бред, это действительно удобная штука, без которой ежегодно умирало по сотне маленьких невинных котят. А что касается for (int n : v) то да, это не деление и не тернарный оператор, это так называемый range-based for, аналог foreach из других языков программирования, или более удобоваримая с точки зрения синтаксиса форма работы с итераторами. И то. и другое позволяет писать значительно более краткий и удобочитаемый код - в первом случае программист избавляется от необходимости перегружать код лишними функциями, единственное предназначение которых - быть единожды вызванными в какие-то вспомогательных целях (кстати немаловажный побочный плюс еще и в том, что нет необходимости искать, где эти вспомогательные функции реализованы, так как их реализация находится там, где они используются), во втором - писать громоздкие конструкции с итераторами и begin() end() для элементарной операции итерации по контейнеру. Также с этими двумя близко связано другое нововведение - ключевое слово auto (точнее, его новый смысл) об этих нововведениях можете почитать тут

Ответ 2



Попробуем разобрать частями, написав код в cтаром стиле. std::generate_n(std::back_insert_iterator>(v), // can be simplified 10, [](){ return std::rand() % 10; }); Можно заменить на for(int i = 0; i < 10; ++i){ v.push_back(std::rand() % 10); } Здесь std::generate_n - функция, применяемая для заполнения контейнера. Она принимает указательна начальный итератор, количество элементо и метод реализации. Соответственно std::back_insert_iterator>(v) - итератор, указывающий на место для первого вставляемого элемента, 10 - количество элементов и { return std::rand() % 10; } - метод генерации этих элементов. Перейдем к следующему кусочку. for (int n : v) std::cout << n << ' '; Заменим на: for(vector::iterator it = v.begin(); it != v.end(); ++it){ std::cout << *it << ' '; } Этот цикл служит для обхода контейнера, так называемый foreach. здесь n - конкретный для итерации элемент контейнера v.

Ответ 3



std::generate_n это такая функция из стандартной библиотеки с тремя параметрами. Ничего необычного. Ей, согласно документации, нужно три параметра - итератор для вставки, кол-во этих вставок и функция-генератор значений для вставки. С вторым параметром проблем не должно быть. Первый параметр - итератор для вставки. По простому говоря, это такая обертка для контейнера, которая может добавлять элементы в конец (для вектора она просто дергает push_back). Третий параметр - сложнее. Это обычная лябда-функция. Но их просто нужно изучить. Переводя на привычный язык, этот участок кода запишется так for (int i = 0; i < 10; i++) v.push_back(std::rand() % 10); Что короче, а что красивее - это дело вкуса и требований. for (int n : v) - а это новомодный foreach. Появился в новом стандарте. Он просто последовательно присваивает n значения вектора и обрабатывает в цикле. То есть, просто for (int i = 0; i < v.size(); i++) { int n = v[i]; // }

пятница, 24 января 2020 г.

Стоит ли применять паттерн итератор

#java #шаблоны_проектирования #итераторы


Доброго времени суток.

Вопрос следующий: имеется двумерный массив объектов. Несколько модулей в программе
регулярно запрашивают какую-то часть этого массива и последовательно перебирают её
элементы. Для некоторых модулей порядок обхода не важен, но для некоторых это критично.
Так например один модуль запрашивает "прямоугольный" кусок этого двумерного массива
и ему нужно дважды пробежаться по каждой строке начиная с верхней. Так вот, уместно
ли применять паттерн итератор в случае, если порядок обхода для его клиентов критически
важен и каждому клиенту может понадобиться установить свой порядок обхода, при этом
придется реализовывать несколько итераторов с разным интерфейсом? И если нет, подскажите
пожалуйста, стоит ли тогда передовать клиентам непосредственно сам двумерный массив
с учетом, что может понадобиться изменить способ хранения данных? Какое архитектурное
решение лучше подойдет в данном случаи?
    


Ответы

Ответ 1



Общие рекомендации Стоит сделать либо один класс с несколькими методами, предоставляющими выборки, либо несколько классов, по одному на вид выборки, и раздать их потребителям. Каждый метод выборки должен возвращать специализированный итератор. Но интерфейсы у итераторов будут одинаковыми: это обычный Java-интерфейс Iterator. По поводу выборки прямоугольной области и двойных итераций по строкам: Стоит сделать так: метод выборки возвращает итератор по объектам типа Row (добавьте какой-либо свой префикс), реализующий интерфейс Iterable. Каждый такой объект имеет ссылку на строку данных и поля first и length, и из него можно получить итератор по такому "слайсу". Таким образом можно итерироваться и по строкам и по элементам: Iterable rows = someQuerier.getRect(left, top, width, height); for (RectRow row : rows) { // многократный проход по одной и той же строке for (int rowPassCount = 0; rowPassCount < maxRowPassCount; rowPassCount += 1) { for (YourItem item : row) { // Ваши действия с элементом } } }

среда, 22 января 2020 г.

Как безопасно добавить элементы в коллекцию при использовании итератора?

#c_sharp #коллекции #итераторы


В коллекцию постоянно добавляются сообщения об изменении в программе и мне нужно
выводить эти изменения в textbox. Для этого использую метод Print, где получаю строку
для вывода.

class Journal
{
    // Коллекция для событий
    private List journal = new List();

    // Добавить событие в коллекцию
    public void Add(string Name, string Type_of_Change)
    {
        journal.Add(new CollectionHandlerEventArgs(Name, Type_of_Change));
    }

    // Обработчик изменений на сервере
    public void ServerChanged(CollectionHandlerEventArgs e)
    {
        CollectionHandlerEventArgs je = new CollectionHandlerEventArgs(e.Name, e.Type_of_Change);
        journal.Add(je);
    }

    // Обработчик изменений клиента
    public void ClientChanged(CollectionHandlerEventArgs e)
    {
        CollectionHandlerEventArgs je = new CollectionHandlerEventArgs(e.Name, e.Type_of_Change);
        journal.Add(je);
    }

    // Получение строки с изменениями
    public string Print()
    {
        string s = null;
        foreach (CollectionHandlerEventArgs j in journal)
        {
            s += j.Name + ": " + j.Type_of_Change + "\n";
        }
        return s;
    }
}


Нашел ошибку в том, что во время итерации нельзя изменять коллекцию, однако мне необходимо
это сделать. Как исправить?
    


Ответы

Ответ 1



Ошибка вызвана изменениями в списке в то время, когда существует энумератор этого списка. В цикле for никакого энумератора не создается. for (int i = 0; i < journal.Count; i++) { CollectionHandlerEventArgs item = journal[i]; s += item.Name + ": " + item.Type_of_Change + "\n"; } Потоко-безопасный вариант: private ConcurrentBag journal = new ConcurrentBag(); ... foreach (CollectionHandlerEventArgs j in journal.ToArray()) { s += j.Name + ": " + j.Type_of_Change + "\n"; }

воскресенье, 12 января 2020 г.

Использование итераторов для проверки элементов массива

#ruby #итераторы


def isfin?
  @matrix[0..@col_count-1][0]==0
end


Как пользоваться итераторами в Ruby? Например, нужно вернуть true, если все элементы
массива [n][0] (где n от 0 до "длина массива - 1") равны нулю. Или в данном случае
лучше использовать простой цикл?

Например, если у нас будет 0..200, и на второй позиции уже не 0, то можно выйти с
false и не просматривать остальные элементы. Или при использовании итераторов это условие
будет автоматически учтено, и медленнее работать не будет?
    


Ответы

Ответ 1



Во-первых, судя по собаке, речь идет о методе собственного класса. Я бы рекомендовал не воротить никакого ООП, пока не знаешь сам язык и stdlib. def isfin? @matrix.all? do |row| row[0] == 0 end end Итератор all? здесь обрывается и возвращает false как только блок do end вернет false. Можно переписать это таким образом, что матрицу сначала транспонируем, и проверяем лишь одномерный массив: def isfin? @matrix.transpose.first.all? do |cell| cell == 0 end end И тогда использование стандартного метода .zero? позволяет записать это короче: def isfin? @matrix.transpose.first.all? &:zero? end А можно .map вместо .tranpose использовать -- это может работать быстрей: def isfin? @matrix.map(&:first).all? &:zero? end

вторник, 31 декабря 2019 г.

Не находит std::begin, std::end

#cpp #массивы #указатели #шаблоны_с++ #итераторы


Пишу простую шаблонную функцию in_array. По замыслу, она должна работать с любыми
типами. Вот код:

template 
bool in_array(T needle, const T* haystack) {
    T *e = std::find(std::begin(haystack), std::end(haystack), needle);
    if (e != std::end(haystack))
        return true;
    else
        return false;
}


Получаю ошибки: 


  std::begin: не найдена соответствующая перегруженная функция


То же для std::end. В чем моя ошибка?
    


Ответы

Ответ 1



Для указателей стандартные функции std::begin и std::end не определены. Имея указатель, в общем случае, нельзя определить, указывает ли он на одиночный объект или на первый объект некоторой последовательности объектов. В виду этого нельзя определить функцию std::end для указателей, так как неизвестно число элементов, которые могут адресоваться указателем. Вы могли бы свою функцию определить следующим образом template bool in_array(T needle, T ( &haystack )[N] ) { auto e = std::find(std::begin(haystack), std::end(haystack), needle); return e != std::end(haystack); } Либо вы можете эту функцию определить как template bool in_array(T needle, T *haystack, size_t n ) { auto e = std::find( haystack, haystack + n, needle); return e != haystack + n; } включив в объявление функции еще один параметр, задающий число элементов в массиве.

Ответ 2



Для указателя эти функции не определены.

вторник, 24 декабря 2019 г.

Зачем нужен __iter__, когда есть __next__?

#python #python_3x #классы #итераторы #дизайн_языка


Я учу python и у меня возник вопрос по итераторам.
Чтобы можно было итерироваться по объекту, у него должен быть метод __iter__, который
вернет объект-итератор.
У объекта-итератора должен быть метод __next__, который будет возвращать следующий
элемент из объекта, по которому итерируемся, либо кидать ошибку StopIteration.
Я встречал только такой код, в котором __iter__ возвращает self.
Например 

class RandomIterator:
    def __iter__(self):
        return self

    def __init__(self, k):
        self.k = k
        self.i = 0

    def __next__(self):
        if self.i < self.k:
            self.i += 1
            return random()
        else:
            raise StopIteration


Вот у меня и возник вопрос, какой смысл от метода __iter__?
    


Ответы

Ответ 1



__iter__() в Python Как вы узнали из урока «Классы и объекты Python», у всех классов есть функция под названием __init__(), которая позволяет вам делать инициализацию при создании объекта. Метод __iter__() действует аналогично, вы можете выполнять операции (инициализацию и т. Д.), Но всегда должны возвращать сам объект итератора. немного хабра Теперь, когда речь зашла о создании собственных последовательностей в Питоне, пришло время поговорить о протоколах. Протоколы немного похожи на интерфейсы в других языках тем, что они предоставляют набор методов, которые вы должны реализовать. Однако, в Питоне протоколы абсолютно ни к чему не обязывают и не требуют обязательно реализовать какое-либо объявление. Наверное, они больше похожи на руководящие указания. Почему мы заговорили о протоколах? Потому, что реализация произвольных контейнерных типов в Питоне влечёт за собой использование некоторых из них. Во-первых, протокол для определения неизменяемых контейнеров: чтобы создать неизменяемый контейнер, вы должны только определить __len__ и __getitem__ (продробнее о них дальше). Протокол изменяемого контейнера требует того же, что и неизменяемого контейнера, плюс __setitem__ и __delitem__. И, наконец, если вы хотите, чтобы ваши объекты можно было перебирать итерацией, вы должны определить __iter__, который возвращает итератор. Этот итератор должен соответствовать протоколу итератора, который требует методов __iter__(возвращает самого себя) и next. __iter__(self) Должен вернуть итератор для контейнера. Итераторы возвращаются в множестве ситуаций, главным образом для встроенной функции iter() и в случае перебора элементов контейнера выражением for x in container:. Итераторы сами по себе объекты и они тоже должны определять метод __iter__, который возвращает self. UPDATE (вернул пример с кодом, ибо попросили в комментах): Вот в примере по 1-й ссылке есть один из вариантов зачем. Когда вам нужно считать кол-во элеметов обработанных или иные связанные операции. Это полезно для уменьшения кол-во дублирования кода (см. принципы языка Python)iter() в Python class MyNumbers: def __iter__(self): self.a = 1 return self def __next__(self): x = self.a self.a += 1 return x А вот ниже мой пример использования __iter__ class Fibbonachi: def __iter__(self): self.cur_val = 0 self.next_val = 1 return self def __next__(self): tmp = self.next_val self.next_val += self.cur_val self.cur_val = tmp return tmp for i in Fibbonachi(): print(i) if i > 100: break # Результат: 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144 в колонку

пятница, 20 декабря 2019 г.

Использование итераторов С++ с массивами

#cpp #итераторы


Возможно, кто-либо может объяснить итераторы и их использование с массивами, или
же дать соответствующую литературу по этой теме?

Т.к. я читал по разным книгам о итераторах, но там идет речь о использовании их совместно
с STL и т.п., а как самому написать - особо такого не написано... Насколько я понял,
то они нужны, чтобы перебирать и т.п. элементы массива. Я правда не знаю смысл в этом,
если вроде бы можно и непосредственно обращаться, ну да ладно, не важно.
Т.е. нужно создать вложенный класс внутри класса, где будет содержаться, скажем, массив?

Если я понял, то в конце концов, когда он написан, то, к примеру, для цикла выведения
массива будет такой код:

for(start = Iterator.begin(); start != end; start++)
{
    cout << *start;
}


Или я что-то путаю?

P.S.: А ещё, если у кого есть книги, где об этом говорится, статьи, то пожалуйста
и их напишите тоже сюда.



class Array
{
private:
    int* p;
public:
    class Iterator
    {
        public:
        Iterator()  
        {
            p = nullptr;
        }
        Iterator(int *pv)
        {
            p = pv;
        }
        int operator *() const
        {
            return *p;
        }
        Iterator operator ++(int)
        {
            int *temp = p;
            return ++temp;
        }
    };

    Array();
    ~Array();
int& operator[] ();
    Iterator begin()
    {
        return Iterator(buffer_)
    }
int* buffer_;

void partial_sort(Array::Iterator start, Iterator end)
{
    start
}


Вот как понять что-то вроде этого... Точнее говоря это наброски, они не совсем мои..
Вот мне нужно сделать примерно такое же, только работающее..



Если говорить поконкретнее насчёт того, что не понимаю...
Вот класс итератор вложенный, в нем какое поле должно быть ?
При перегрузке Iterator operator ++(int) это он типо должен будет перебирать элементы
массива же, да?
А если я хочу перегрузить ==?
Я пробовал писать что-то вроде:  

Iterator operator==(Iterator it1, Iterator it2)


Чтобы сравнивать их на равенство, но не получается - ошибка "много аргументов".
ДА и ещё не до конца понимаю как его реализовать..
Т.е. допустим функции вывода, сортировок вместо того, чтобы передавать массив и его
длину мне нужно будет передавать 2 итератора, верно? Один из них указывает на начало,
другой на конец, да?
А вывод массива в таком случае выглядел бы с итераторами так:

for(start ???; start != end; start++)
  cout << *start;

    


Ответы

Ответ 1



Вот, собственно, пример итератора. Этот код вырезан из SGI STL, почищен от всяких подробностей, чтобы оставить суть. Тут можно посмотреть что и как в итераторах должно быть в принципе: #include // нужен только лишь для типа std::size_t class iterator { protected: int* p; public: explicit iterator(int* __i) : p(__i) { } // Forward iterator requirements const int& operator*() const { return *p; } int& operator*() { return *p; } int* operator->() const { return p; } // prefix increment (++it) iterator& operator++() { ++p; return *this; } // postfix increment (it++) iterator operator++(int) { return iterator(p++); } // Bidirectional iterator requirements // prefix decrement (--it) iterator& operator--() { --p; return *this; } // postfix decrement (it--) iterator operator--(int) { return iterator(p--); } // Random access iterator requirements const int& operator[](const std::size_t& __n) const { return p[__n]; } int& operator[](const std::size_t& __n) { return p[__n]; } iterator& operator+=(const std::size_t& __n) { p += __n; return *this; } iterator operator+(const std::size_t& __n) const { return iterator(p + __n); } iterator& operator-=(const std::size_t& __n) { p -= __n; return *this; } iterator operator-(const std::size_t& __n) const { return iterator(p - __n); } int* base() const { return p; } }; // Forward iterator requirements inline bool operator==(const iterator& __lhs, const iterator& __rhs) { return __lhs.base() == __rhs.base(); } inline bool operator!=(const iterator& __lhs, const iterator& __rhs) { return __lhs.base() != __rhs.base(); } // Random access iterator requirements inline bool operator<(const iterator& __lhs, const iterator& __rhs) { return __lhs.base() < __rhs.base(); } inline bool operator>(const iterator& __lhs, const iterator& __rhs) { return __lhs.base() > __rhs.base(); } inline bool operator<=(const iterator& __lhs, const iterator& __rhs) { return __lhs.base() <= __rhs.base(); } inline bool operator>=(const iterator& __lhs, const iterator& __rhs) { return __lhs.base() >= __rhs.base(); } inline std::size_t operator-(const iterator& __lhs, const iterator& __rhs) { return __lhs.base() - __rhs.base(); } inline iterator operator+( std::size_t __n, const iterator& __i) { return iterator(__i.base() + __n); } Обратите внимание на explicit конструктор, на то какие операторы перегружены для того, чтобы итератор удовлетворял концепциям: forward iterator random access iterator bidirectional iterator

Ответ 2



Итераторы призваны предоставлять доступ к членам контейнеров, они могут быть использованы способом, похожим на манипуляции указателями. Например, можно использовать итератор для прохода по всем элементам вектора. Есть несколько разных типов итераторов. Каждый класс контейнеров связан с типом итератора, и каждый из алгоритмов STL использует определенный тип итератора. Например, векторы связаны с итераторами с произвольным доступом, значит, они могут использовать алгоритмы, требующие произвольного доступа. Так как итераторы с произвольным доступом включают в себя все свойства других итераторов, то векторы также могут использовать алгоритмы, написанные для других итераторов. Код в примере создает итератор и использует его в векторе: vector the_vector; vector::iterator the_iterator; for( int i=0; i < 10; i++ ) the_vector.push_back(i); int total = 0; the_iterator = the_vector.begin(); while( the_iterator != the_vector.end() ) { total += *the_iterator; ++the_iterator; } cout << "Итого=" << total << endl; Получить доступ к элементам контейнера можно путем разыменования итератора.

Ответ 3



Массив - это конкретная форма хранения данных. Отличается тем, что у нас есть числовой индекс у каждого элемента. Причем этот индекс уникален. Обычно эти индексы представляют собой целые числа от некоего минимального до некоего максимального с каким-то фиксированным шагом. int a[100]; for (int i = 0; i < 100; i++) { std::cout<

Ответ 4



В принципе итератор, это просто расширенная концепция указателя и все алгоритмы STL, работающие с итераторами должны работать и с указателями напрямую: #include #include void go( int value ) { printf("%d\n", value); } int main() { int a[5] = { 0, 1, 2, 3, 4 }; std::for_each( &a[0], &a[5], &go ); return 0; }

Ответ 5



class MyIterator; class MyArray{ public: MyIterator* Iterate(); // возвращает пассивный итератор, index в 0. bool More(MyIterator*); // true если еще есть элементы, иначе - false int Next(MyIterator*); // возвратим текущий элемент массива, index++ ... }; class MyIterator { int index; // здесь мы будем хранить номер текущего элемента // для конкретного итератора, т.к. итераторов мы можем завести много. ... } MyArray* collection = new MyArray(100);// сделаем-ка массив на 100 элементов, // для этого конструктор коллекции должен принимать кол-во элементов ... MyIterator* iter = collection->Iterate(); //сделаем итератор ... while (collection->More(iter)) // пока еще есть элементы std::cout<Next(iter)<

Ответ 6



Есть классная книга: "С++. Методики программирования Шилдта". там примерно половина посвящена итераторам

понедельник, 2 декабря 2019 г.

Зачем нужны функции std::advance, next, prev?

#cpp #итераторы


В стандартной библиотеке С++ есть функции std::advance, std::next, std::prev.
Зачем они нужны и в каких случаях следует их использовать?
    


Ответы

Ответ 1



Функция std::advance появилась ранее функций std::next и std::prev еще в стандарте C++ 2003, в то время как последние две функции появились в стандарте C++ 2011. Функция std::advance имеет следующее объявление template void advance(InputIterator& i, Distance n); Как видно из объявления, функция меняет тот итератор, который передан ей по ссылке в качестве первого параметра. Однако, как показала практика, очень часто требуется создать новый итератор, который является предшествующим или последующим относительно текущего итератора. В этом случае приходилось прибегать к такому псевдо-коду (я использую термин псевдо-код, так как в нем я задействую ключевое слово auto, которое в стандарте C++ 2003 еще не имело того значения, которое оно имеет в стандарте C++ 2011), так как в общем случае итераторы за исключением итераторов произвольного доступа не имели операции сложения с целочисленными значениями: auto next = current; advance( next, n ); где n - некоторое целое число. Например, рассмотрим задачу найти максимальный элемент во второй половине элементов некоторого списка #include #include #include // ... std::list lst; // инициализация списка некоторыми значениями std::list::iterator it = lst.begin(); std::advance( it, lst.size() / 2 ); it = std::max_element( it, lst.end() ); Так как функция std::advance имеет тип возвращаемого значения void, и она меняет переданный ей в качестве аргумента итератор, то ее неудобно использовать с алгоритмами. Требуются дополнительные объявления и предложения кода, чтобы вызвать какой-нибудь алгоритм. Например, вот как может выглядеть вызов алгоритма std::rotate для списка с использованием функции std::advance #include #include #include // ... std::list lst; // инициализация списка некоторыми значениями std::list::iterator middle = lst.begin(); std::advance( middle, lst.size() / 2 ); std::rotate( lst.begin(), middle, lst.end() ); Кроме того само слово advance не совсем удачное, когда дело доходит до вычисления итераторов, которые предшествуют заданному итератору. В этом случае требуется указывать отрицательное значение для второго аргумента функции, что может стать источником ошибок. Например, std::advance( middle, -1 ); Из этого предложения трудно сделать вывод, является ли -1 опечаткой или же это значение действительно выражает намерение программиста. Такие имена, как prev или next более ясно выражают намерения программиста и делают код более читабельным. Поэтому было предложено ввести функции std::prev и std::next в стандарт C++ 2011. Более того эти функции возвращают итератор, а потому их можно встраивать в вызовы алгоритмов. Они не изменяют итераторы, на основе которых функции возвращают новые итераторы. Предыдущий пример вызова алгоритма std::rotate для списка теперь с использованием этих функций можно записать в одну строчку #include #include #include // ... std::list lst; // инициализация списка некоторыми значениями std::rotate( lst.begin(), std::next( lst.begin(), lst.size() / 2 ), lst.end() ); То есть можно получать новые итераторы или выражения с итераторами "на лету", не засоряя код объявлениями промежуточных переменных, которые требуются лишь для вычисления аргументов алгоритмов. Итераторы произвольного доступа можно складывать с целочисленными выражениями, чтобы получить новый итератор. Например, std::vector sequence = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; std::rotate( sequence.begin(), sequence.begin() + sequence.size() / 2, sequence.end() ); Однако этот код не является гибким. Если по какой-нибудь причине вы захотите использовать другой контейнер, который не имеет итераторов произвольного доступа, то вам предложение с вызовом алгоритма придется менять. Значительно лучше будет если даже для итераторов произвольного доступа вы будете использовать данные обобщенные функции std::vector sequence = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; std::rotate( sequence.begin(), std::next( sequence.begin(), sequence.size() / 2 ), sequence.end() ); Особенно эти функции незаменимы, когда вы пишите шаблонный код для произвольного типа итераторов. Обе функции std::next и std::prev имеют для второго параметра аргумент по умолчанию: template ForwardIterator next(ForwardIterator x, typename std::iterator_traits::difference_type n = 1); template BidirectionalIterator prev(BidirectionalIterator x, typename std::iterator_traits::difference_type n = 1); Поэтому эти функции очень удобно использовать, когда надо получить следующий или предыдущий итератор. Например, std::vector v = { /* некоторые значения */ }; auto after_first = std::next( v.begin() ); auto before_last = std::prev( v.end() ); Было бы логичным, чтобы функция std::advance также имела для второго параметра аргумент по умолчанию. Тогда вместо выражения, как, например, auto it = v.begin(); std::advance( it, 1 ); можно было бы записать проще auto it = v.begin(); std::advance( it ); И слово advance в этом случае соответствовало бы своему непосредственному значению. Мною было сделано такое предложение по включению в объявление функции std::advance значения аргумента по умолчанию равного 1 для второго параметра функции. С данным моим предложением по изменению стандарта C++ относительно функции std::advance можно ознакомиться по этой ссылке

Ответ 2



Существуют различные категории итераторов, такие как RandomAccessIterator или ForwardIterator. Категория итератора определяет какие операции поддерживаются итератором: RandomAccessIterator умеет it + n, it += n, ++it, it--, и т.п.; BidirectionalIterator может перемещаться только на один элемент: ++it, it--; ForwardIterator может перемещаться только вперед: ++it или it++. Перемещение на несколько элементов Функции std::advance, std::next и std::prev упрощают перемещение между несколькими элементами для BidirectionalIterator и более простых категорий итераторов. iter = std::next(iter, n); // Эквивалентно iter = iter + n; iter = std::prev(iter, n); // Эквивалентно iter = iter - n; std::advance(iter, n); // Эквивалентно iter += n; Для RandomAccessIterator эти функции не дают никаких преимуществ, по этому нет смысла применять их вместо операторов + или +=. Перемещение на один элемент В требованиях к категориям итераторов, операции ++ и -- определены следующим образом: Выражение | Тип ----------+----- ++r | X& Там образом операции ++ и -- определены только для переменных (l-value), и не определены для r-value значений, например результатов функций. По этому выражение вида ++f() может не скомпилироваться: ++std::min_element(first, last) // НЕ РЕКОМЕНДУЕТСЯ: может не скомпилироваться std::next(std::min_element(first, last)) // OK: next скопирует результат find() // и вызовет "++" у l-value В остальных случаях нет никаких причин использовать next и prev вместо ++ и --.

среда, 27 ноября 2019 г.

Что такое итераторы и зачем они нужны

#итераторы #c++


Вот не могу понять основное предназначение итераторов . Погуглив , все равное не понял.

Пожалуйста объясните:


Что такое итератор?
Зачем он нужен?
Преимущества на указателем
Как его описать программно в коде? (то есть сделать свой итератор
подобный библиотечным).

    


Ответы

Ответ 1



Смотрите. Пускай у вас есть контейнер. Неважно какой: map, vector, set. Он содержит набор элементов. И вы хотите сослаться не на весь контейнер, а на какое-то место в этом наборе элементов. Так чтобы от этого места можно было перейти вперёд/назад, и что-то в этом месте сделать: изменить элемент, вставить элемент, удалить элемент. Как это сделать? Для массива вы в таких случаях пользуетесь индексом. set внутри является красно-чёрным деревом, так что вам понадобится ссылка на узел этого дерева. unordered_map использует хэш-таблицу, так что вам нужна пара из хэш-индекса и указателя на элемент внутри bucket'а. Чтобы не приходилось писать алгоритмы, специфические для каждого контейнера, и были придуманы итераторы. Итератор — структура данных, которая «указывает» на некоторый элемент контейнера, и (для некоторых контейнеров) умеет переходить к предыдущему/следующему элементу. Если вы хотите реализовать итератор, помните, что существуют разные типы итераторов, в зависимости от операций, которые они предоставляют. Вот список возможных типов. Если вы, например, хотите реализовать RandomAccessIterator, вам придётся определить конструктор копирования, оператор присваивания, деструктор, операции ==, !=, *, ->, конструктор без аргументов, ++, --, +=, + (2 шт.), -=, - (2 шт.), <, >, <=, >=. (Другие типы итераторов попроще.) Кроме того, вам придётся специфицировать std::iterator_traits, где It — тип вашего итератора. Вот вам заготовка для собственного контейнера на SO. Немало, правда?

Ответ 2



Итератор - это объект, который позволяет перемещаться (итерироваться) по элементам некоторой последовательности. Использование таких объектов классифицируется как паттерн программирования Итератор. Последовательность может быть как готовым набором объектов в памяти, так и состоять объектов которые создаются "на лету" при перемещении итератора (например читаются из файла). В отличие от разнообразных последовательностей элементов (массивы, списки, файлы), итераторы имеют одинаковый интерфейс: получение текущего элемента, перемещение к следующему. Это позволяет писать более общие алгоритмы, которые работают с любыми итераторами, поддерживающими этот минимальный набор функций. Итераторы стандартной библиотеки C++ повторяют интерфейс указателя. Это позволяет использовать указатели на элементы массива в качестве итераторов. При этом большинство алгоритмов используют только некоторый минимальный набор операций, например только перемещение вперед. Этот набор операций называется категорией, список всех категорий итераторов перечислен тут. Варианты написания своего итератора есть в ответах к этому вопросу.

понедельник, 8 июля 2019 г.

Проблема в архитектуре приложения: итерации и циклы

Постараюсь описать всё как можно покороче. Вот цикл программы, в котором выполняется обновление сообщений от Windows окна:
while( msg.message != WM_QUIT ) { if( PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) ) { TranslateMessage( &msg ); DispatchMessage( &msg ); } }
Кто работал с Виндой – знает. И, собственно, выполнение самой программы. Например, мне необходимо проиграть аудио файл в ф-ции подобной этой:
playSound( const string& file_name ) { while( !engOfFile() ) { // There is sound are playing... } }
Однако нам мешает следующее: в playSound(...) есть цикл который повторяет итерации на протяжении воспроизведения песни. Получается, что пока итерирует цикл принятия смс-оk от окна, sound are not playing. Так же само и наоборот: пока sound are playing, программу сложно закрыть, кроме как через диспетчер задач (и виден круглый курсор). В итоге: оба цикла мешают друг другу
playSound( "music.ogg" ); Window->update( );
// Anyway, we've got an issue.
Window->update( ); playSound( "music.ogg" );
Что посоветуете? Уже думал над отдельным потоком, но реализовать не вышло. Есть какие-то идеи, кто писал код под Windows?


Ответ

Посмотрите пример Playing and Recording Sound via the Wave API
Смотрите сразу playback wrapper functions
Суть тут для воспроизведения и записи звука примерно одинаковая: готовим буферы, в которые последовательно загружаем звуковые данные и передаем эти буферы в систему, а она уже Вас уведомляет о их завершении или ошибках через колбеки или через оконные уведомления.

Формат ogg, насколько я знаю, напрямую не поддерживается Windows. PlaySound, например конвертировать ogg точно не будет. Вам придется конвертировать его перед воспроизведением, в WAV, например. Для этого тоже есть свой API (смотрите функции с префиком acm). Подобрать кодек можно с помощью вызова acmFormatSuggest
Подробности - в MSDN: Converting Data from One Format to Another

Самый простой способ асинхронно проиграть файл, на мой взгляд - PlaySound
PlaySound(TEXT("recycle.wav"), NULL, SND_FILENAME | SND_ASYNC);
но учитывайте предыдущее замечание относительно этой функции касательно ogg

вторник, 4 июня 2019 г.

Обвертка над итератором для преобразования типа

Есть два типа A и B, между объектами этих типов установлено соответствие. Есть набор X значений типа А и итератор по этому набору. Необходимо с минимальными трудозатратами на основе итератора X получить итератор по значениям типа B.
В общем по-простому говоря, есть контейнер типа A, из итератора А нужно получить итератор B, потому что клиент принимает итераторы B.
Например:
typedef std::pair A; typedef float B;
B A2B(const A & item) // соответствие между A и B { return item.second; }
std::vector X; input_iterator bi = magic_iterator_wrapper(A2B, X.begin());
Чем может быть magic_iterator_wrapper?


Ответ

Можно использовать boost::transform_iterator
#include #include #include #include
using A = std::pair; using B = float;
float A2B(const A & item) { return item.second; }
template auto make_transform_iterator(I i, F f) { return boost::transform_iterator{i, f}; }
int main() { std::vector
v = {{0, 1}, {0, 20}};
auto first = make_transform_iterator(v.begin(), A2B); auto last = make_transform_iterator(v.end(), A2B);
std::cout << std::accumulate(first, last, 0) << '
'; }
>>> То же на реальном компиляторе <<<

понедельник, 27 мая 2019 г.

Итерация по элементам строки: вытащить элемент, который будет числом и длина которого будет больше 4х символов

Добрый день. Подскажите, могу ли я итерироваться по элементам строки? Например есть строка а = 'qqqq 12qw3 12 12345', отсюда необходимо вытащить элемент, который будет числом и длина которого будет больше 4х символов. Возможно, стоит использовать модуль re, но я не могу понять, как задать в нём условие выбора элемента по его длине.


Ответ

Строка:
In [56]: a = 'qqqq a987654xx321aa 12qw3 12 12345 zz 1234567'
Если необходимо вернуть только первое число длина которого больше 4х символов:
In [72]: re.search(r'\b(\d{5,})\b', a).group(0) Out[72]: '12345'
Вариант не использующий RegEx
In [68]: [s for s in a.split() if s.isdecimal() and len(s) > 4][0] Out[68]: '12345'
Если необходимо вернуть все числа длина которых больше 4х символов:
In [57]: re.findall(r'\b(\d{5,})\b', a) Out[57]: ['12345', '1234567']
или так, если считать числом 987654 присутствующим в a987654xx321aa
In [58]: re.findall(r'(\d{5,})', a) Out[58]: ['987654', '12345', '1234567']

понедельник, 18 марта 2019 г.

Стоит ли применять паттерн итератор

Доброго времени суток.
Вопрос следующий: имеется двумерный массив объектов. Несколько модулей в программе регулярно запрашивают какую-то часть этого массива и последовательно перебирают её элементы. Для некоторых модулей порядок обхода не важен, но для некоторых это критично. Так например один модуль запрашивает "прямоугольный" кусок этого двумерного массива и ему нужно дважды пробежаться по каждой строке начиная с верхней. Так вот, уместно ли применять паттерн итератор в случае, если порядок обхода для его клиентов критически важен и каждому клиенту может понадобиться установить свой порядок обхода, при этом придется реализовывать несколько итераторов с разным интерфейсом? И если нет, подскажите пожалуйста, стоит ли тогда передовать клиентам непосредственно сам двумерный массив с учетом, что может понадобиться изменить способ хранения данных? Какое архитектурное решение лучше подойдет в данном случаи?


Ответ

Общие рекомендации
Стоит сделать либо один класс с несколькими методами, предоставляющими выборки, либо несколько классов, по одному на вид выборки, и раздать их потребителям.
Каждый метод выборки должен возвращать специализированный итератор. Но интерфейсы у итераторов будут одинаковыми: это обычный Java-интерфейс Iterator
По поводу выборки прямоугольной области и двойных итераций по строкам:
Стоит сделать так: метод выборки возвращает итератор по объектам типа Row (добавьте какой-либо свой префикс), реализующий интерфейс Iterable. Каждый такой объект имеет ссылку на строку данных и поля first и length, и из него можно получить итератор по такому "слайсу". Таким образом можно итерироваться и по строкам и по элементам:
Iterable rows = someQuerier.getRect(left, top, width, height); for (RectRow row : rows) { // многократный проход по одной и той же строке for (int rowPassCount = 0; rowPassCount < maxRowPassCount; rowPassCount += 1) { for (YourItem item : row) { // Ваши действия с элементом } } }

воскресенье, 10 марта 2019 г.

Как безопасно добавить элементы в коллекцию при использовании итератора?

В коллекцию постоянно добавляются сообщения об изменении в программе и мне нужно выводить эти изменения в textbox. Для этого использую метод Print, где получаю строку для вывода.
class Journal { // Коллекция для событий private List journal = new List();
// Добавить событие в коллекцию public void Add(string Name, string Type_of_Change) { journal.Add(new CollectionHandlerEventArgs(Name, Type_of_Change)); }
// Обработчик изменений на сервере public void ServerChanged(CollectionHandlerEventArgs e) { CollectionHandlerEventArgs je = new CollectionHandlerEventArgs(e.Name, e.Type_of_Change); journal.Add(je); }
// Обработчик изменений клиента public void ClientChanged(CollectionHandlerEventArgs e) { CollectionHandlerEventArgs je = new CollectionHandlerEventArgs(e.Name, e.Type_of_Change); journal.Add(je); }
// Получение строки с изменениями public string Print() { string s = null; foreach (CollectionHandlerEventArgs j in journal) { s += j.Name + ": " + j.Type_of_Change + "
"; } return s; } }
Нашел ошибку в том, что во время итерации нельзя изменять коллекцию, однако мне необходимо это сделать. Как исправить?


Ответ

Ошибка вызвана изменениями в списке в то время, когда существует энумератор этого списка. В цикле for никакого энумератора не создается.
for (int i = 0; i < journal.Count; i++) { CollectionHandlerEventArgs item = journal[i]; s += item.Name + ": " + item.Type_of_Change + "
"; }
Потоко-безопасный вариант:
private ConcurrentBag journal = new ConcurrentBag();
...
foreach (CollectionHandlerEventArgs j in journal.ToArray()) { s += j.Name + ": " + j.Type_of_Change + "
"; }

суббота, 9 марта 2019 г.

Использование итераторов для проверки элементов массива

def isfin? @matrix[0..@col_count-1][0]==0 end
Как пользоваться итераторами в Ruby? Например, нужно вернуть true, если все элементы массива [n][0] (где n от 0 до "длина массива - 1") равны нулю. Или в данном случае лучше использовать простой цикл?
Например, если у нас будет 0..200, и на второй позиции уже не 0, то можно выйти с false и не просматривать остальные элементы. Или при использовании итераторов это условие будет автоматически учтено, и медленнее работать не будет?


Ответ

Во-первых, судя по собаке, речь идет о методе собственного класса. Я бы рекомендовал не воротить никакого ООП, пока не знаешь сам язык и stdlib.
def isfin? @matrix.all? do |row| row[0] == 0 end end
Итератор all? здесь обрывается и возвращает false как только блок do end вернет false
Можно переписать это таким образом, что матрицу сначала транспонируем, и проверяем лишь одномерный массив:
def isfin? @matrix.transpose.first.all? do |cell| cell == 0 end end
И тогда использование стандартного метода .zero? позволяет записать это короче:
def isfin? @matrix.transpose.first.all? &:zero? end
А можно .map вместо .tranpose использовать -- это может работать быстрей:
def isfin? @matrix.map(&:first).all? &:zero? end

понедельник, 17 декабря 2018 г.

Не находит std::begin, std::end

Пишу простую шаблонную функцию in_array. По замыслу, она должна работать с любыми типами. Вот код:
template bool in_array(T needle, const T* haystack) { T *e = std::find(std::begin(haystack), std::end(haystack), needle); if (e != std::end(haystack)) return true; else return false; }
Получаю ошибки:
std::begin: не найдена соответствующая перегруженная функция
То же для std::end. В чем моя ошибка?


Ответ

Для указателей стандартные функции std::begin и std::end не определены.
Имея указатель, в общем случае, нельзя определить, указывает ли он на одиночный объект или на первый объект некоторой последовательности объектов. В виду этого нельзя определить функцию std::end для указателей, так как неизвестно число элементов, которые могут адресоваться указателем.
Вы могли бы свою функцию определить следующим образом
template bool in_array(T needle, T ( &haystack )[N] ) { auto e = std::find(std::begin(haystack), std::end(haystack), needle);
return e != std::end(haystack); }
Либо вы можете эту функцию определить как
template bool in_array(T needle, T *haystack, size_t n ) { auto e = std::find( haystack, haystack + n, needle);
return e != haystack + n; }
включив в объявление функции еще один параметр, задающий число элементов в массиве.

пятница, 14 декабря 2018 г.

Использование итераторов С++ с массивами

Возможно, кто-либо может объяснить итераторы и их использование с массивами, или же дать соответствующую литературу по этой теме?
Т.к. я читал по разным книгам о итераторах, но там идет речь о использовании их совместно с STL и т.п., а как самому написать - особо такого не написано... Насколько я понял, то они нужны, чтобы перебирать и т.п. элементы массива. Я правда не знаю смысл в этом, если вроде бы можно и непосредственно обращаться, ну да ладно, не важно. Т.е. нужно создать вложенный класс внутри класса, где будет содержаться, скажем, массив?
Если я понял, то в конце концов, когда он написан, то, к примеру, для цикла выведения массива будет такой код:
for(start = Iterator.begin(); start != end; start++) { cout << *start; }
Или я что-то путаю?
P.S.: А ещё, если у кого есть книги, где об этом говорится, статьи, то пожалуйста и их напишите тоже сюда.

class Array { private: int* p; public: class Iterator { public: Iterator() { p = nullptr; } Iterator(int *pv) { p = pv; } int operator *() const { return *p; } Iterator operator ++(int) { int *temp = p; return ++temp; } };
Array(); ~Array(); int& operator[] (); Iterator begin() { return Iterator(buffer_) } int* buffer_;
void partial_sort(Array::Iterator start, Iterator end) { start }
Вот как понять что-то вроде этого... Точнее говоря это наброски, они не совсем мои.. Вот мне нужно сделать примерно такое же, только работающее..

Если говорить поконкретнее насчёт того, что не понимаю... Вот класс итератор вложенный, в нем какое поле должно быть ? При перегрузке Iterator operator ++(int) это он типо должен будет перебирать элементы массива же, да? А если я хочу перегрузить ==? Я пробовал писать что-то вроде:
Iterator operator==(Iterator it1, Iterator it2)
Чтобы сравнивать их на равенство, но не получается - ошибка "много аргументов". ДА и ещё не до конца понимаю как его реализовать.. Т.е. допустим функции вывода, сортировок вместо того, чтобы передавать массив и его длину мне нужно будет передавать 2 итератора, верно? Один из них указывает на начало, другой на конец, да? А вывод массива в таком случае выглядел бы с итераторами так:
for(start ???; start != end; start++) cout << *start;


Ответ

Вот, собственно, пример итератора. Этот код вырезан из SGI STL, почищен от всяких подробностей, чтобы оставить суть. Тут можно посмотреть что и как в итераторах должно быть в принципе: #include // нужен только лишь для типа std::size_t
class iterator { protected: int* p;
public: explicit iterator(int* __i) : p(__i) { }
// Forward iterator requirements const int& operator*() const { return *p; }
int& operator*() { return *p; }
int* operator->() const { return p; }
// prefix increment (++it) iterator& operator++() { ++p; return *this; }
// postfix increment (it++) iterator operator++(int) { return iterator(p++); }
// Bidirectional iterator requirements
// prefix decrement (--it) iterator& operator--() { --p; return *this; }
// postfix decrement (it--) iterator operator--(int) { return iterator(p--); }
// Random access iterator requirements const int& operator[](const std::size_t& __n) const { return p[__n]; }
int& operator[](const std::size_t& __n) { return p[__n]; }
iterator& operator+=(const std::size_t& __n) { p += __n; return *this; }
iterator operator+(const std::size_t& __n) const { return iterator(p + __n); }
iterator& operator-=(const std::size_t& __n) { p -= __n; return *this; }
iterator operator-(const std::size_t& __n) const { return iterator(p - __n); }
int* base() const { return p; } };
// Forward iterator requirements inline bool operator==(const iterator& __lhs, const iterator& __rhs) { return __lhs.base() == __rhs.base(); }
inline bool operator!=(const iterator& __lhs, const iterator& __rhs) { return __lhs.base() != __rhs.base(); }
// Random access iterator requirements inline bool operator<(const iterator& __lhs, const iterator& __rhs) { return __lhs.base() < __rhs.base(); }
inline bool operator>(const iterator& __lhs, const iterator& __rhs) { return __lhs.base() > __rhs.base(); }
inline bool operator<=(const iterator& __lhs, const iterator& __rhs) { return __lhs.base() <= __rhs.base(); }
inline bool operator>=(const iterator& __lhs, const iterator& __rhs) { return __lhs.base() >= __rhs.base(); }
inline std::size_t operator-(const iterator& __lhs, const iterator& __rhs) { return __lhs.base() - __rhs.base(); }
inline iterator operator+( std::size_t __n, const iterator& __i) { return iterator(__i.base() + __n); } Обратите внимание на explicit конструктор, на то какие операторы перегружены для того, чтобы итератор удовлетворял концепциям: forward iterator random access iterator bidirectional iterator