Текст книги "Введение в стандартную библиотеку шаблонов C++. Описание, примеры использования, учебные задачи"
Автор книги: Михаил Абрамян
Жанр: Учебная литература, Детские книги
сообщить о неприемлемом содержимом
Текущая страница: 5 (всего у книги 14 страниц) [доступный отрывок для чтения: 5 страниц]
Функциональный объект-обертка для бинарной операции / с параметрами типа const T& и возвращаемым значением типа T.
Функциональный объект-обертка для бинарной операции == с параметрами типа const T& и возвращаемым значением типа bool.
Функциональный объект-обертка для бинарной операции > с параметрами типа const T& и возвращаемым значением типа bool.
Функциональный объект-обертка для бинарной операции >= с параметрами типа const T& и возвращаемым значением типа bool.
Функциональный объект-обертка для бинарной операции < с параметрами типа const T& и возвращаемым значением типа bool.
Функциональный объект-обертка для бинарной операции <= с параметрами типа const T& и возвращаемым значением типа bool.
Функциональный объект-обертка для бинарной операции && с параметрами типа const T& и возвращаемым значением типа bool.
Функциональный объект-обертка для унарной операции ! с параметром типа const T& и возвращаемым значением типа bool.
Функциональный объект-обертка для бинарной операции || с параметрами типа const T& и возвращаемым значением типа bool.
Функциональный объект-обертка для бинарной операции – с параметрами типа const T& и возвращаемым значением типа T.
Функциональный объект-обертка для бинарной операции % с параметрами типа const T& и возвращаемым значением типа T.
Функциональный объект-обертка для бинарной операции * с параметрами типа const T& и возвращаемым значением типа T.
Функциональный объект-обертка для унарной операции – с параметром типа const T& и возвращаемым значением типа T.
Функциональный объект-обертка для бинарной операции != с параметрами типа const T& и возвращаемым значением типа bool.
Функциональный объект-обертка для бинарной операции + с параметрами типа const T& и возвращаемым значением типа T.
Раздел 2. Использование библиотеки STL
2.1. Знакомство с итераторами и алгоритмами: STL1Iter17
2.1.1. Установка задачника, создание проекта-заготовки и знакомство с заданиемЗадания группы STL1Iter знакомят с такими базовыми средствами стандартной библиотеки, как итераторы и алгоритмы.
Итераторы представляют собой объекты, обеспечивающие перемещение по последовательности и доступ к ее элементам (можно сказать, что итератор – это абстракция понятия указателя). Хотя обычно итераторы используются при работе с контейнерами; наиболее простые виды итераторов – итераторы для чтения и итераторы для записи – могут применяться в программе для доступа к потокам чтения/записи, поэтому начать знакомство с итераторами можно без предварительного изучения контейнеров STL (которым посвящены группы STL2Seq, STL4Str и STL5Assoc).
Впрочем, сами по себе итераторы не позволяют воспользоваться всеми возможностями стандартной библиотеки: для этого их необходимо применять совместно с алгоритмами – функциями из библиотеки STL, которые обеспечивают выполнение различных стандартных операций над последовательностями данных и используют итераторы для доступа к обрабатываемым последовательностям. Благодаря применению итераторов алгоритмы не «привязываются» к конкретному виду последовательности (например, контейнеру определенного типа), а могут обрабатывать любые последовательности, поддерживающие работу с итераторами (даже если они не хранятся в памяти, а извлекаются из некоторого потока ввода или, наоборот, после генерации элементов сразу передаются в поток вывода).
В заданиях группы STL1Iter для обработки исходных наборов данных требуется использовать простейшие алгоритмы STL, которые применяются непосредственно к потокам ввода-вывода через связанные с ними итераторы. В качестве потоков ввода-вывода используются стандартные файловые потоки, а также специальный поток pt, определенный в задачнике Programming Taskbook.
Большинство важных особенностей заданий группы STL1Iter можно проиллюстрировать на примере выполнения задания STL1Iter17.
STL1Iter17. Дана строка name и набор символов. Записать в текстовый файл с именем name удвоенные кодовые значения всех символов из исходного набора в том же порядке, добавляя после каждого числа один пробел. Использовать итераторы ptin_iterator, ostream_iterator и алгоритм transform.
Перед тем как приступить к выполнению заданий из задачника Programming Taskbook for STL, необходимо установить на компьютер универсальный задачник Programming Taskbook и задачник Programming Taskbook for STL, являющийся дополнением универсального задачника. Дистрибутивные пакеты для установки задачников можно скачать с сайта электронного задачника http://ptaskbook.com/ (страница «Главная | Услуги | Скачивание дистрибутивов»). Задачник PT for STL может использоваться как с полным вариантом универсального задачника, так и с его мини-вариантом, не требующим последующей регистрации. После установки универсального задачника будет автоматически запущена программа его настройки PT4Setup, в которой будут указаны все среды программирования (из числа поддерживаемых задачником), обнаруженные на компьютере. Необходимо убедиться, что в число этих сред входит хотя бы одна среда для языка C++. В этой же программе можно указать рабочий каталог, в котором будут выполняться задания (по умолчанию рабочий каталог размещается на диске C и имеет имя PT4Work), а также задать имя студента, которое будет храниться в файле с результатами выполнения заданий. Заметим, что программа PT4Setup, как и все другие компоненты задачника, доступна из его меню «Пуск | Программы | Programming Taskbook 4».
После установки универсального задачника Programming Taskbook следует установить его дополнение Programming Taskbook for STL.
Выполнение задания с применением задачника Programming Taskbook начинается с создания проекта-заготовки для выбранного задания. Для создания заготовки предназначен программный модуль PT4Load, входящий в состав задачника. Вызвать этот модуль можно с помощью ярлыка Load.lnk, который автоматически создается в рабочем каталоге студента.
После запуска модуля PT4Load на экране появится его окно, в котором будут перечислены все доступные группы заданий (рис. 1).
Рис. 1. Окно модуля PT4Load
Заметим, что с помощью модуля PT4Load можно не только создать заготовку для задания, но и определить любое количество новых рабочих каталогов; для этого достаточно нажать на кнопку и выбрать существующий или создать новый каталог, после чего указать имя студента, связанное с этим рабочим каталогом).
В заголовке окна указывается имя текущей среды программирования и номер ее версии. Приведенный рисунок соответствует настройке, при которой текущей средой является среда Microsoft Visual Studio 2012 для языка C++.
При выполнении заданий, посвященных стандартной библиотеке шаблонов C++, можно использовать любые среды программирования для языка C++, которые поддерживаются электронным задачником. В версии 4.17 задачника это среды Microsoft Visual Studio 2008, 2010, 2012, 2013, 2015, 2017 и Code::Blocks 13. Если указана среда, отличная от требуемой, следует вызвать контекстное меню модуля PT4Load (щелкнув в его окне правой кнопкой мыши или нажав на кнопку ) и выбрать нужную среду из появившегося списка. В дальнейшем будем предполагать, что текущей средой является одна из версий среды Visual Studio.
В списке групп заданий должна содержаться группа STL1Iter. Ее отсутствие может объясняться двумя причинами: либо в качестве текущего языка выбран язык, отличный от C++, либо на компьютере не установлено дополнение Programming Taskbook for STL.
После ввода имени задания (в нашем случае STL1Iter17) кнопка «Загрузка» в окне PT4Load станет доступной, и, нажав ее (или клавишу [Enter]), мы создадим заготовку для указанного задания, которая немедленно загрузится в среду Visual Studio. Созданный проект включает несколько файлов, однако для решения задачи нам потребуется только файл с именем STL1Iter17.cpp. Именно этот файл будет загружен в редактор среды Visual Studio.
Приведем текст файла STL1Iter17.cpp (этот текст будет одинаковым для всех сред программирования, которые можно использовать для решения задачи):
Файл начинается с директивы подключения заголовочного файла pt4.h, в котором содержатся описания дополнительных функций, обеспечивающих взаимодействие учебной программы с задачником (в число этих функций входит, в частности, функция Task, предназначенная дли инициализации требуемого задания).
Затем указывается директива using namespace std, благодаря которой в последующем тексте программы можно не уточнять стандартное пространство имен std для связанных с ним типов (заметим, что все типы библиотеки STL, за очень небольшим исключением, определены именно в пространстве имен std).
Наконец, описывается функция Solve, в которой требуется запрограммировать решение задачи; в этой функции уже содержится вызов функции Task, инициализирующей задание.
Следует обратить внимание на то, что в тексте файла STL1Iter17.cpp отсутствует описание стартовой функции (которая обычно имеет имя main или, для среды Visual Studio, WinMain). Данная функция, разумеется, входит в созданный проект, но поскольку корректировать ее содержание не требуется, ее описание перенесено в другой файл (а именно в файл pt4.h).
Для запуска созданной программы достаточно нажать клавишу [F5] (при использовании среды Code::Blocks используется клавиша [F9]).
Примечание 1. Если при попытке запуска программы система Visual Studio пытается выполнить другое действие, то следует щелкнуть правой кнопкой мыши на имени проекта ptprj в окне «Solution Explorer» («Обозреватель решений») и в появившемся контекстном меню выполнить команду «Set as StartUp Project» («Назначить запускаемым проектом»).
После запуска программы на экране появится окно задачника (рис. 2). Приведенный на рисунке вид соответствует режиму с динамической компоновкой, появившемуся в версии 4.11 задачника.
В дальнейшем мы всегда будем использовать режим с динамической компоновкой. Если окно отображается в «старом» режиме с фиксированной компоновкой (рис. 3), то для переключения на новый режим достаточно нажать клавишу [F4].
Рис. 2. Окно задачника в режиме с динамической компоновкой
Рис. 3. Окно задачника в режиме с фиксированной компоновкой
Поскольку в программе не выполняются действия по вводу и выводу данных, запуск программы считается ознакомительным. При ознакомительном запуске в окне задачника отображаются три раздела: с формулировкой задания, исходными данными и примером верного решения.
Все исходные данные выделяются особым цветом, чтобы отличить их от комментариев: если для окна установлен цветовой режим «на белом фоне» (как на приведенных выше рисунках), то данные выделяются синим цветом; в режиме «на черном фоне» данные выделяются желтым цветом. Для переключения цветового режима достаточно нажать клавишу [F3].
Запуск программы позволяет ознакомиться с образцом исходных данных и с соответствующим этим исходным данным примером правильного решения. В нашем случае в набор исходных данных входит имя текстового файла, в который требуется записать полученную последовательность (это имя снабжено комментарием «name =» и заключено в двойные кавычки), количество элементов в исходном символьном наборе (это количество заключено в круглые скобки) и сами символьные элементы набора (каждый из которых заключен в одинарные кавычки). Во всех заданиях, входящих в задачник Programming Taskbook for STL все исходные последовательности, предлагаемые задачником (за исключением тех, которые содержатся в исходных текстовых файлах), задаются аналогичным образом: вначале указывается количество элементов последовательности, а затем – значения самих элементов (на экране количество элементов заключается в скобки и отделяется от списка значений двоеточием), причем значения могут располагаться на нескольких экранных строках.
Символьные данные заключаются в одинарные кавычки, а строковые – в двойные, что соответствует представлению символьных и строковых констант в языке C++. Использование кавычек позволяет, в частности, «увидеть» пустые строки, входящие в наборы исходных или результирующих данных, или строки, начинающиеся или оканчивающиеся пробелами (как в примере верного решения, приведенном на предыдущих рисунках).
В разделе «Пример верного решения» содержится единственная текстовая строка, которая должна быть записана в результирующий файл; эта строка содержит удвоенные коды всех символов из исходного набора, причем после каждого числа располагается по одному пробелу.
Каждая строка текстового файла заключается в кавычки и выводится на отдельной экранной строке; рядом с первой строкой файла указывается ее порядковый номер, равный 1. В разделах исходных данных и результатов содержимое файлов выделяется бирюзовым цветом (цветовое выделение позволяет отличить файловые строки от других данных, а также комментариев). В разделе с правильным решением все данные выводятся серым цветом, чтобы отличить их от «настоящих» данных, найденных учебной программой.
Примечание 2. Если в задании используются текстовые файлы, содержащие несколько строк, то в окне задачника по умолчанию отображаются только начальные строки этих файлов, после которых указывается многоточие «…». Для того чтобы отобразить на экране все строки, содержащиеся в текстовом файле, достаточно выполнить двойной щелчок мышью в разделе окна задачника с файловыми данными. Для просмотра заданий, включающих файловые данные большого размера, в задачнике предусмотрен набор дополнительных средств; эти средства подробно описываются в п. 2.5.1 при обсуждении задания STL7Mix4. В заданиях из предыдущих групп (в том числе из группы STL1Iter) файлы либо не используются, либо имеют небольшой размер, поэтому в применении специальных средств для их просмотра нет необходимости.
Для выхода из программы достаточно нажать кнопку «Выход», клавишу [Esc] или клавишу [F5], т. е. ту же клавишу, которая обеспечивает запуск программы из среды Visual Studio (в случае использования среды Code::Blocks окно задачника можно закрыть, нажав клавишу [F9]).
Чтобы более подробно ознакомиться с заданием, можно использовать два специальных режима задачника: демонстрационный режим и режим отображения заданий в формате html.
Для запуска программы в демонстрационном режиме достаточно дополнить параметр метода Task символом «?» (в нашем случае вызов метода примет вид Task("STL1Iter17?");). Окно задачника в демонстрационном режиме имеет дополнительные кнопки, позволяющие переходить к предыдущему или последующему заданию выбранной группы, а также отображать на экране различные наборы исходных данных и связанные с ними образцы правильного решения (рис. 4).
Рис. 4. Окно задачника в демонстрационном режиме
Для отображения задания в формате html достаточно дополнить параметр метода Task символом «#» (в нашем случае вызов метода примет вид Task(«STL1Iter17#»);). При запуске полученной программы будет запущен html-браузер, используемый в системе по умолчанию, и в него загрузится html-страница, содержащая формулировку задания и текст преамбулы к соответствующей группе заданий.
Режим html-страницы удобен в нескольких отношениях. Во-первых, только в этом режиме можно ознакомиться с преамбулами к группе заданий и входящим в нее подгруппам и тем самым получить дополнительные сведения, которые могут оказаться полезными при выполнении заданий. Во-вторых, окно браузера с html-страницей не требуется закрывать для того, чтобы продолжить работу над заданием; таким образом, с помощью этого окна можно в любой момент ознакомиться с формулировкой задания, даже если текущее состояние программы не позволяет откомпилировать ее и запустить на выполнение.
Имеется возможность отобразить в html-режиме все задания, входящие в некоторую группу. Для этого в параметре метода Task следует удалить номер задания, оставив только имя группы и символ «#» (например, Task(«STL1Iter#»);).
Закончив на этом обзор возможностей задачника, предназначенных для формирования проекта-заготовки и ознакомления с выбранным заданием, перейдем к описанию самого процесса решения.
2.1.2. Выполнение заданияНачнем выполнение задания с добавления к программе новых директив #include. Поскольку задание связано с записью данных в текстовый файл (и использованием итераторов, связанных с файловыми потоками), подключим заголовок <fstream>. Так как при выполнении задания требуется использовать один из алгоритмов STL (а именно transform), подключим заголовок <algorithm>. В результате начальная часть файла STL1Iter 17.cpp (до описания функции Solve) примет следующий вид:
Заметим, что подключать заголовок <string> не требуется, хотя мы и будем использовать в программе текстовые строки.
Теперь реализуем ввод исходных данных. По условию задачи вначале дается строка – имя результирующего файла. Введем это имя в строковую переменную s, используя поток ввода pt (этот поток определен в заголовочном файле pt4.h и связан с электронным задачником). В результате функция Solve примет следующий вид:
При запуске полученного варианта программы окно задачника будет содержать сообщение о том, что введены не все требуемые исходные данные, а фон сообщения станет оранжевым (рис. 5).
Рис. 5. Окно задачника с сообщением об ошибочном решении
Сообщения об ошибках всегда выводятся на фоне, цвет которого является одним из оттенков красного. Например, оранжевый цвет связывается с ситуацией, при которой введено или выведено недостаточное количество данных, малиновый цвет – если введено или выведено избыточное количество данных, а фиолетовый – если была попытка ввести или вывести данные неверного типа. Таким же цветом выделяется и заголовок раздела окна, связанного с обнаруженной ошибкой (в нашем случае так выделяется заголовок с исходными данными). В разделе индикаторов, расположенном над разделом с формулировкой задания, тоже выводится оранжевый прямоугольный маркер, причем он отображается в левой части раздела (эта часть содержит информацию о вводе данных). Там же указывается, что был фактически прочитан только один элемент исходных данных из имеющихся 19.
Следует обратить внимание на то, что в средней части раздела индикаторов отсутствует информация о выведенных данных. Это связано с тем, что по условию задачи не требуется пересылать результаты задачнику; вместо этого необходимо создать новый файл и записать полученные результаты в созданный файл. В такой ситуации задачник не следит за количеством выведенных данных, а просто проверяет содержимое созданного файла. Впрочем, в нашем случае до проверки результатов дело не дошло, так как раньше была выявлена ошибка, связанная с недостаточным количеством введенных данных.
Для ввода остальных данных можно было бы прочесть количество элементов, а затем в цикле читать сами элементы и сразу их обрабатывать (или сохранять в массиве или другом подходящем контейнере). Однако в задании предлагается использовать для ввода другой способ, основанный на применении итераторов, – ведь именно такой способ соответствует «идеологии» стандартной библиотеки STL. Так как исходные данные генерируются задачником, для их ввода надо использовать специальный итератор для потока ввода pt, имеющий имя ptin_iterator. Итератор является шаблонным классом, который надо специализировать типом вводимых элементов; в данном случае это тип char (заметим, что аналогичным образом специализируются и стандартные итераторы файлового ввода).
Кроме того, при создании итератора обычно указывается набор параметров, определяющий свойства итератора. Если требуется создать итератор ptin_iterator, связанный с началом последовательности, то необходимо указать целочисленный параметр, равный количеству элементов этой последовательности. Предусмотрено особое значение для этого параметра, равное 0; в этом случае итератор сам определяет количество элементов, считывая его из потока ввода pt перед вводом самих элементов. Заметим, что для итераторов файлового ввода, связанных с началом последовательности, также нужно указывать параметр – имя файлового потока (количество элементов в данном случае не указывается, так как итератор файлового ввода читает данные до конца файла).
Итератор ptin_iterator, связываемый с концом последовательности, не имеет параметров (как и итератор, связываемый с концом файлового потока).
Итак, для указания начала и конца последовательности символов, получаемой из потока pt, при условии, что перед элементами этой последовательности передается их количество, следует использовать итераторы ptin_iterator<char>(0) и ptin_iterator<char>() соответственно. Чтобы дважды не использовать длинное имя типа, удобно определить псевдоним для требуемой специализации шаблона, например:
Как проверить, что эти итераторы обеспечат правильный ввод исходных данных? Удобным способом является отладочная печать, позволяющая выводить информацию в специальный раздел окна задачника (раздел отладки). Для отладочной печати предусмотрены функции Show и ShowLine, определенные в файле pt4.h, причем для них имеются шаблонные варианты, обеспечивающие вывод последовательности с использованием ее итераторов (в этом отношении шаблонные варианты методов Show и ShowLine с параметрами-итераторами ведут себя аналогично стандартным алгоритмам из библиотеки STL).
Добавим в конец функции Solve вызов функции Show, обеспечивающий вывод исходной последовательности в раздел отладки. При задании параметров функции Show будем использовать ранее определенный псевдоним ptin для итератора ввода. Получим следующий вариант функции Solve (перед функцией должно располагаться приведенное выше определение псевдонима ptin):
Заметим, что если бы мы использовали функцию ShowLine, то каждый элемент последовательности выводился бы на новой строке раздела отладки. В вариантах функций Show и ShowLine с параметрами-итераторами можно также указывать необязательный третий параметр – строку-комментарий, которая выводится перед первым элементом последовательности.
После запуска программы окно задачника примет вид, приведенный на рис. 6.
Рис. 6. Окно задачника при правильном вводе исходных данных
Теперь наша программа правильно вводит все исходные данные, хотя и не выводит результаты. Можно считать, что мы успешно прошли первый этап решения, связанный с вводом данных. Чтобы отметить этот факт, в разделе индикаторов, связанном с вводом данных, выводится зеленый маркер, а информационная панель содержит текст на светло-синем фоне: «Запуск с правильным вводом данных: все требуемые исходные данные введены, результирующий файл не создан». Поскольку результаты не выведены, в окне отсутствует раздел полученных результатов.
Следует также обратить внимание на нижнюю часть окна задачника. В ней появился раздел отладки, где выведены все элементы исходной последовательности.
В нашем варианте программы введенные данные не сохранялись в памяти, а сразу перенаправлялись функции Show для вывода в разделе отладки. Аналогичным образом можно перенаправить эти данные в результирующий текстовый файл. Однако перед записью в файл надо преобразовать полученные данные в соответствии с условием задачи. Для преобразования элементов исходной последовательности и получения новой последовательности, содержащей преобразованные элементы, в библиотеке STL имеется алгоритм transform, который, согласно формулировке задачи STL1Iter17, следует использовать при ее решении.
Алгоритм transform реализован в двух вариантах (см. п. 1.3.3); нас интересует вариант, принимающий одну входную последовательность:
Первые два параметра этого алгоритма задают начало и конец исходной последовательности (в виде двух итераторов), третий параметр содержит итератор, связанный с началом преобразованной последовательности, а последний параметр представляет собой функциональный объект с одним параметром, определяющий правило, по которому должны преобразовываться элементы исходной последовательности. В простейшем случае в качестве функционального объекта можно использовать указатель на обычную функцию.
Алгоритм transform возвращает итератор, указывающий на конец преобразованной последовательности.
Преобразованную последовательность не обязательно сохранять в памяти. Если использовать в качестве третьего параметра алгоритма transform итератор, связанный с файловым потоком, то преобразованная последовательность будет записана в соответствующий файл. Именно это действие и требуется выполнить в нашем задании.
Итак, для решения задания нам осталось определить функцию (назовем ее f), преобразующую символы в удвоенные значения их кодов, создать файловый поток вывода os (связав его с именем файла s) и вызвать алгоритм transform, передав ему требуемые параметры:
При описании функции f мы учли тот факт, что в языке C++ (в отличие от многих современных языков программирования) возможно неявное преобразование типа char в тип int.
В дополнительном комментарии нуждается второй, необязательный параметр конструктора ostream_iterator: в нем можно указать разделитель, который будет автоматически добавляться после записи в поток каждого элемента последовательности. По умолчанию разделитель отсутствует.
Заметим также, что при выполнении задания в системе Visual Studio 2008 в конструкторе класса ofstream необходимо преобразовать строку s к типу const char*, используя соответствующий метод класса string:
Последующие версии Visual Studio и компилятор GCC, включенный в среду Code::Blocks 13, поддерживают стандарт C++11, согласно которому указанное преобразование выполнять не требуется.
При запуске полученной программы на экране появится окно прогресса тестирования, в котором отображается число пройденных тестов (рис. 7).
Рис. 7. Окно с индикатором прогресса тестирования
Наша программа является правильной, поэтому все пять требуемых тестов будут пройдены успешно, после чего на экране появится окно задачника с сообщением о том, что задание выполнено (рис. 8).
Рис. 8. Окно задачника с сообщением об успешном выполнении задания
Не закрывая окна задачника, можно просмотреть историю выполнения задания. Для этого достаточно нажать клавишу [F2] или щелкнуть мышью на метке «Результаты» в правом верхнем углу окна. На экране появится окно еще одного вспомогательного программного модуля задачника – PT4Results, в котором будут перечислены все запуски нашей программы:
Символ «c», указанный перед датой, означает, что задание выполнялось на языке С++.
Внимание! Это не конец книги.
Если начало книги вам понравилось, то полную версию можно приобрести у нашего партнёра - распространителя легального контента. Поддержите автора!Правообладателям!
Данное произведение размещено по согласованию с ООО "ЛитРес" (20% исходного текста). Если размещение книги нарушает чьи-либо права, то сообщите об этом.Читателям!
Оплатили, но не знаете что делать дальше?