Страницы

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

вторник, 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]; // }

Комментариев нет:

Отправить комментарий