|
Программирование >> Разработка устойчивых систем
tempiate<class Assoc. class Count, class Gen> void assocGen n(Assoc& a. Count n. Gen g) { whileCn-- > 0) a.insertCgO): #endif ASSOCGEN H III:- Вместо итераторов мы передаем сам класс контейнера (разумеется, по ссылке). Из этого примера следуют два важных урока. Первый урок: если алгоритм не делает того, что вам нужно, скопируйте наиболее близкий по смыслу образец и внесите исправления. Заголовочные файлы STL находятся под рукой, так что большая часть работы за вас уже сделана. Второй урок более специфичен: если хорошенько подумать, обычно удается решить задачу средствами STL, не изобретая ничего нового. Например, наша задача может быть решена при помощи итератора вставки (создаваемого вызовом inserterO), который включает элементы в контейнер вызовом insert() вместо operator=. Это решение не является разновидностью итератора frontjnsertjterator или backjnsertjterator, потому что эти итераторы используют функции push Jront() и push back() соответственно. Каждый итератор вставки характеризуется функцией, требуемой для вставки, и в нашем примере нужна именно функция insert(). Следующий пример демонстрирует заполнение данными отображений и множеств, хотя он будет работать и с мультиотображениями и мультимножествами. Начнем обходится без создания и уничтожения дополнительных объектов. С другой стороны, он труднее пишется и читается. Заполнение ассоциативных контейнеров данными Вы уже видели, как удобны шаблоны fiU(), filLn(), generate() и generate n(), из заголовка <algorithm> для заполнения данными последовательных контейнеров (векторов, списков и деков). Однако эти алгоритмы присваивают значения элементам последовательных контейнеров оператором =, тогда как добавление элементов в ассоциативные контейнеры производится соответствующими функциями insert(). Следовательно, используемый по умолчанию механизм присваивания порождает проблемы при попытке применить эти алгоритмы к ассоциативным контейнерам. Первое очевидное решение - продублировать алгоритмы fill/generate и создать новые алгоритмы, предназначенные для ассоциативных контейнеров. Впрочем, дублируются только алгоритмы filLn() и generate n() (алгоритмы fiU() и generate() копируют интервалы, а для ассоциативных контейнеров это бессмысленно), но задача решается просто - за образец можно взять заголовочный файл <algorithm>: : C07:assocGen.h Аналоги fm n() и generate n() для ассоциативных контейнеров. #ifndef ASSOCGENJ #define ASSOCGEN H tempiate<class Assoc. class Count, class T> void assocFill n(Assoc& a, Count n. const T& val) { whileCn-- > 0) a.insert(val): с определения пары шаблонных генераторов (на первый взгляд это явный перебор, но такие шаблоны часто удобны, поэтому их определения лучше вынести в заголовочный файл). : C07:SimpleGenerators.h Обобщенные генераторы (включая генератор пар). #include <iostream> #include <utility> Генератор, увеличивающий свое текущее значение: tempiate<typename Т> class IncrGen { Т 1: public: IncrGen(T ii) : i (ii) {} T operatorOO { return i++: } Генератор для создания объектов STL pa1r<>: tempiate<typename Tl. typename T2> class PairGen { Tl i: T2 j: public: PairGen(Tl ii. T2 jj) : i(ii). j(jj) {} std: :pair<Tl.T2> operatorOO { return std::pair<Tl.T2>(i++. j++): namespace std { Обобщенный глобальный оператор для вывода произвольных объектов STL pair<>: tempiate<typename F. typename S> ostream& operator (ostream& os. const pair<F.S>& p) { return OS p.first \t p.second endl: } III:- Оба генератора предполагают, что тип Т поддерживает инкремент, и создают новые значения по исходным данным при помощи оператора++. Шаблон PairGen возвращает объект pair библиотеки STL, который напрямую включается в отображение или мультиотображение функцией insert(). Последняя функция представляет собой обобщенную версию оператора для ostream. Наш оператор позволяет вывести любой объект pair при условии, что каждый элемент пары поддерживает потоковый оператор (из-за некоторых особенностей разрешения имен, о которых рассказывалось в главе 5, он должен находиться в пространстве std; мы вернемся к этой теме при описании программы Thesaurus.срр позднее в этой главе). Как видно из следующего примера, это позволяет использовать алгоритм сору() для вывода элементов отображения: : C07:AssocInserter.cpp Итератор вставки делает возможным использование алгоритмов fill n() и generate n() с ассоциативными контейнерами. #incl ude <iterator> linclude <iostream> #include <algorithm> iinclude <set> iinclude <map> #1nc1ude SimpleGenerators.h using namespace std: int mainO { set<int> s: fin n(inserter(s. s.beginO). 10. 47): generate n(inserter(s, s.beginO). 10. IncrGen<int>(12)): copyCs.beginO. s.endO. ostream iterator<int>(cout. \n )): map<int. int> m: fin n(inserter(m. m.beginO). 10. make pair(90.120)): generate n(inserter(m, m.beginO). 10. PairGen<int. int>(3. 9)): copy(m.beginO. m.endO. ostream iterator<pai r<int.int> >(cout. \n )): } III:- Передача итератора во втором аргументе inserter помогает оптимизировать процесс вставки - итератор рекомендует, с какой позиции следует начинать поиск (вместо того, чтобы всегда начинать его с корня базового дерева). Однако итератор вставки может использоваться с разными типами контейнеров, и для неассоциативных контейнеров итератор обязателен. Обратите внимание на создание итератора ostreamjterator для вывода объекта pair - без определения операторной функции operator он бы не сработал. Поскольку ostreamjterator является шаблоном, он автоматически специализируется для типа pair<intint>. Отображения в обычных массивах элемент определяется целочисленным индексом, задающим его позицию в последовательности однотипных элементов. Отображение (контейнер тар) является ассоциативным массивом; это означает, что он позволяет ассоциировать один объект с другим (по аналогии с тем, как индекс связывается с элементом в массиве). Но вместо простого индексирования выборка в отображениях осуществляется по объекту-ключу! В следующем примере подсчитывается число вхождений слов в текстовом файле. Таким образом, индекс (объект string) представляет слово, а искомое значение - объект со счетчиком числа вхождений. В обычных контейнерах вроде векторов или списков элемент представляет собой самостоятельный объект данных. Но в отображениях один элемент состоит из двух компонентов: ключа (по которому осуществляется поиск в форме отобра-жение[ключ]) и значения, ассоциированного с ключом. Чтобы перебрать все содержимое отображение и вывести каждую пару ключ/значение , следует использовать итератор, разыменование которого дает пару (объект pair) с ключом и значением. Доступ к компонентам пары осуществляется через переменные first и second. Аналогичный принцип упаковки двух элементов также используется при вставке элементов в отображения, но в этом случае объект pair создается в контексте конкретного отображения и называется valuejype. Таким образом, в одном из
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |