[БЕЗ_ЗВУКА] В предыдущем видео мы с вами познакомились с технологией variadic templates, которая позволяет писать функции с переменным, неизвестным заранее количеством аргументов. Давайте попробуем применить эту технологию для того, чтобы написать EmplaceBack в нашем векторе. EmplaceBack будет очень похож на PushBack с той лишь разницей, что PushBack принимает на вход один элемент, а EmplaceBack будет принимать, вообще говоря, несколько аргументов конструктора. Поэтому я просто скопирую код PushBack, напишу к нему шаблонную шапку, скажу, что здесь будет переменное количество шаблонных элементов. Я буду принимать их по константной ссылке, назовем их Args. По новому стандарту EmplaceBack должна возвращать ссылку на вновь вставленный элемент, это удобно. И вот здесь, где мы используем размещающий оператор new вместо конструктора копирования типа T я теперь буду использовать конструктор, которому на вход передаются вот эти аргументы. Поэтому вот этот пакет аргументов Args я здесь просто разверну. А для того чтобы запомнить тот элемент, который я вставил, можно просто вот здесь сохранить соответствующий указатель и вернуть разыменованный elem. Давайте проверим, как будет работать эта функция с нашей структурой Point. Вот у меня уже готова тестовая программа, где структура Point, которую мы пытались в предыдущем видео вставить в обычный вектор, а сейчас мы попробуем ее вставить в наш новый вектор с нашей новой функцией EmplaceBack. Компилируем и запускаем. Ура, мы видим, что действительно один элемент в вектор вставлен. Однако давайте теперь попробуем рассмотреть пример посложнее. Давайте попробуем вставлять в наш вектор не структуру, Point, а какой-нибудь более сложный объект, например, класс File. Если вы помните, в «Коричневом поясе» мы с вами писали обертку над файлом. Вот здесь пример такой обертки. Я тут написал только конструкторы, и они, конечно же, не открывают файл, а всего лишь пишут в какой-то переданный лог сообщения. Но нам этого будет достаточно. Смотрите, у нашего класса File есть конструктор, который принимает на вход условно имя файла и обязательно какой-то лог, в который он будет писать сообщение об ошибке. Это может быть просто поток вывода, скажем, ostream. И будет конструктор перемещения, для того чтобы мы могли забрать владение файлом у какого-нибудь другого временного файла. Например, по результату работы какой-то функции. Обычный конструктор копирования будет запрещен. Давайте попробуем положить в вектор несколько таких файлов. Смотрите, в первом случае я с помощью функции emplace_back кладу в обычный пока что вектор файл, явно передавая два аргумента конструктора: строчку с его названием и поток вывода cout. В другом примере я пытаюсь положить файл, который помечен как временный, к которому применена функция move. Давайте проверим, что со стандартным вектором такие трюки проходят. Да, вот мы видим на экране сообщение, что открыт файл 1, открыт файл 2, и потом вызван конструктор перемещения, который действительно переместил из переменной F содержимое в новый файл, который будет лежать в векторе. Конечно, вместо этого последнего emplace_back мы могли бы использовать перегруженную версию push_back. Но уж давайте заставим работать emplace_back. Теперь давайте попробуем переключиться на наш вектор, который мы только что написали. Согласно стилю у нас функции именуются иначе, поэтому мне придется сделать несколько замен. Reserve, EmplaceBack, и вот вроде бы все готово. И внезапно наша программа не компилируется, и в сообщениях об ошибке мы видим проблемы внутри нашего размещающего оператора new, внутри вызова конструктора. И на самом деле эти проблемы связаны вот с чем. Если вы внимательно посмотрите на код той версии EmplaceBack, который мы написали, вы увидите, что здесь мы принимаем аргументы по константной ссылке. А теперь давайте вернемся к нашему классу File и посмотрим, как там принимались аргументы в конструкторе. Глядите: по константной ссылке здесь принимается только первый аргумент первого конструктора. Другой аргумент принимается по обычной ссылке. А для второй версии конструктора здесь вообще используется ссылка на временный объект: R Value Reference. Вот оказывается, что когда мы объявляем какую-то шаблонную функцию, то, вообще говоря, сам тип T забывает информацию о том, была ли на этом типе константность или какого типа ссылка там была. И вот мы выбрали: функция EmplaceBack принимает все по константной ссылке, и поэтому наша функция работает только для тех случаев, когда там передаются какие-то явные конкретные значения. Или какие-то аргументы, к которым можно привязать константную ссылку. А вот для временного объекта File или для этого потока, который по обычной ссылке должен быть сюда передан, эту константность снять не получается, поэтому компилятор и ругается. В следующем видео мы узнаем, как правильно решать эту проблему.