[БЕЗ_ЗВУКА] Продолжим изучать шаблоны классов на примере шаблона IteratorRange. Давайте сделаем вот что. Мы пока что шаблон IteratorRange используем только вот здесь, внутри нашей функции Head. Но этот шаблон более мощный, он позволяет хранить не только префикс вектора, но и какой-то произвольный диапазон, какой-то произвольный диапазон внутри вектора. Например, мы можем захотеть по какой-то причине обратиться к суффиксу нашего вектора, ко второй его половине. И как бы мы могли это сделать? Мы должны написать вот что. IteratorRange, шаблон, теперь мы его инстанцируем, vector < int >::iterator, собственно, мы его инстанцируем этим типом, типом итератора, second_half, вторая половина вектора. И передаем параметры, v.begin + + v.size / 2, v.end. Компилируется, компилируется, правда, компилятор ругается, что мы никак эту переменную не используем, но код корректный. На что тут можно обратить внимание? Что для объявления переменной second_half нам пришлось написать вот столько много букв, потому что нам надо указать шаблон, надо указать, чем мы его инстанцируем, тип, который мы инстанцируем, тоже достаточно большой и громоздкий — это vector< int >::iterator. И, естественно, так писать не очень-то удобно, потому что код становится громоздким, и его тяжело читать. И мы можем подумать, а как можно решить эту проблему, можно ли пользоваться нашим шаблоном, но как-то более компактно, с необходимостью меньше печатать. И здесь давайте мы вспомним с вами такую вещь. У нас есть шаблоны классов, есть шаблоны функций. И вот, например, у нас есть шаблон функции Head. Это шаблон, у него есть параметр T, но при этом, когда мы вызываем функцию Head вот здесь, мы не указываем в угловых скобках тип, которым, на который будет заменено значение T. Компилятор этот тип выводит за нас. То же самое здесь с функцией RangeSize. Опять же вот RangeSize, мы просто передаем в нее конкретный тип, который возвращает функция Head, и компилятор по этому типу понимает, с каким типом T нужно инстанцировать шаблон RangeSize. То есть для шаблонов функций компилятор сам выводит шаблонные аргументы, и мы можем этой способностью компилятора воспользоваться, чтобы упростить инстанцирование нашего шаблона IteratorRange. Мы можем написать так называемую порождающую функцию. Смотрите, как она выглядит. Мы пишем template <typename Iterator>, IteratorRange <Iterator> MakeRange, MakeRange. И она принимает у нас два параметра: Iterator begin, Iterator end, и возвращает IteratorRange<Iterator> {begin, end}. Вот так мы, такую функцию, такой шаблон функции мы написали. И вот здесь при объявлении переменной second_half мы можем сделать вот что, мы можем написать auto second_half = MakeRange от вот этих вот параметров. Компилируем, это компилируется. Это компилируется, и, например, мы можем пройтись по второй половине нашего вектора v и вывести, убедиться, что у нас там правильно все сформировалось, построилось. Так, у нас... Давайте не будем выводить здесь RangeSize, он нам больше не нужен. Вот вывелось 4, 4, 5. Собственно, здесь у нас вывелся весь вектор, здесь вывелась его вторая половина, 4, 4, 5, то есть действительно создается правильный диапазон. И смотрите, что мы сделали, мы написали функцию, шаблон функции MakeRange, с помощью его вызова проинициализировали переменную second_half, указав в качестве ее типа auto. Код стал короче. При этом компилятор все делает за нас. Он сам по вызову функции MakeRange понимаем тип итератора и с этим типом инстанцирует шаблон IteratorRange. И таким образом мы с помощью порождающей функции смогли сделать наш код короче. Давайте подведем итоги. В этом видео мы с вами познакомились с порождающими функциями, которые позволяют возложить на компилятор выведение шаблонных типов при инстанцировании шаблона класса. Какие преимущества у порождающих функций? Собственно, они сокращают код и избавляют нас от необходимости больше печатать по клавишам. Но у порождающих функций есть некоторые недостатки. Во-первых, их нужно писать самостоятельно, то есть для каждого шаблона класса, который у нас есть, нам приходится рядом отдельно писать порождающую функцию, чтобы она выполняла свою работу. Кроме того, как у меня здесь приведено на экране, какой приведен пример, из записи auto, переменная, равно, MakeRange, что-то там, не очевидно, какой тип имеет переменная, в данном случае full. То есть нам нужно пойти в объявление функции MakeRange и посмотреть, что она возвращает. Это такой, пусть не глобальный, не фатальный, но все-таки недостаток порождающей функции. В следующем видео мы познакомимся с еще одним способом перекладывания выведения шаблонных типов на компилятор.