|
Программирование >> Разработка устойчивых систем
Вместо this-> может использоваться любое допустимое уточнение, например, Sortable::at() или vector<T>::at(). Важно наличие уточнения, а не его конкретный вид. чае обязательно (этот вопрос рассматривается в разделе Разрешение имен этой главы, а также в объяснении к примеру PriorityQueue6.cpp в главе 7). Здесь приведена тестовая программа для файла Sortable.h, в которой используется генератор случайных чисел Urand (см. выше): : C05:Sortable.cpp {bor} (из-за присутствия bitset в Urand.h) Тестирование специализированных шаблонов #include <cstddef> linclude <iostream> linclude Sortable.h linclude Urand.h using namespace std: Idefine asz(a) (sizeof a / sizeof a[0]) char* words[] - { is , running , big , dog , a . }: char* words2[] - { this , that , theother . }: int mainO { Sortable<int> is: Urand<47> rand: for(size t i = 0: i < 15: ++i) is.push back(rnd()): for(size t i - 0: i < is.sizeO: ++i) cout is[i] : cout endl: is.sortO: for(size t i = 0: i < is.sizeO: ++i) cout is[i] : cout endl: Использование частичной специализации шаблона: Sortable<string*> ss: for(size t i = 0: i < asz(words): ++i) ss.push back(new string(words[i])): for(size t i = 0: i < ss.sizeO: ++i) cout *ss[i] : cout endl: ss.sortO: for(size t i - 0: i < ss.sizeO: i++) { cout *ss[i] : delete ss[i]: cout endl: Использование полной специализации char*: Sortable<char*> scp: for(size t i = 0: i < asz(words2): ++i) scp.push back(words2[i]): for(size t i - 0: i < scp.sizeO: ++i) cout scp[i] : cout endl: scp.sortO; for(size t i = 0: i < scp.sizeO: ++i) cout scp[i] : cout endl; } III:- Bo всех специализациях задействованы разные версии шаблона: Sortable<int> использует основной шаблон, а Sortable<string*> - неполную специализацию для указателей, Sortable<char*> - полную специализацию для char*. Без этой полной специализации у вас могло бы сложиться обманчивое впечатление, будто все работает правильно - массив words правильно сортируется в строку а big dog is running*, поскольку частичная специализация ограничивается сравнением первых символов массивов. Однако на примере массива words2 такая сортировка уже не работает. Ограничение объема генерируемого кода Каждый раз, когда в программе определяется специализация шаблона класса, компилятор генерирует код из определения класса для конкретной специализации вместе со всеми функциями, вызываемыми в программе. При этом генерируются только те функции класса, которые вызываются в программе. И это вполне логично, как показывает следующий пример: : С05:Delayed Instantiation.срр Генерируется только код используемых функций шаблонов классов. class X { public: void f() {} class Y { public: void gO {} template <typename T> class Z { T t: public: void aO { t.fO: } void b() { t.gO: } int mainO { Z<X> zx: zx.aO: Код Z<X>::b() не генерируется Z<Y> zy: zy.bO: Код Z<Y>::a() не генерируется } III:- Хотя шаблон Z вроде бы использует обе функции шаблона Т (f() и д()), программа успешно компилируется, а это означает, что код Z<X>::a() генерируется только при явном вызове этой функции для zx (если бы при этом также генерировался код Z<X>::b(), то компилятор выдал бы сообщение об ошибке вызова несуществующей функции Х::д()). Аналогично, вызов zy.b() не генерирует Z<Y>::a(). Следовательно, шаблон Z может использоваться для обоих классов (X и Y). Если бы все функции класса генерировались непосредственно при специализации, это бы существенно ограничило возможности применения многих шаблонов. Допустим, у нас имеется шаблонный контейнер Stack, и в программе используются специализации int, int* и char*. В результате три версии кода Stack будут сгенерированы компилятором и скомпонованы с вашей программой. Как отмечалось ранее, шаблоны нужны прежде всего для того, чтобы избежать ручного дублирования кода; однако код все равно дублируется, просто компилятор генерирует его за вас. Основную часть реализации для указателей можно выделить в единый класс, используя комбинацию полной и частичной специализации. Идея заключается в том, чтобы определить полную специализацию для void*, а затем создать неполные специализации для остальных типов; это позволит применять общий код для разных типов. Следующий пример демонстрирует эту методику: : C05:Nobloat.h Совместное использование кода при хранении указателей в стеке #ifndef NOBLOAT H #define NOBLOAT H #inc1ude <cassert> #inc1ude <cstddef> #1nc1ude <cstring> Основной шаблон tempiate<cl ass T> class Stack { T* data: std::s1ze t count: std::size t capacity: enum {INIT = 5}: public: StackО { count = 0: capacity = INIT: data = new T[INIT]: void pushCconst T& t) { if (count == capacity) { Выделение дополнительной памяти std::size t newCapacity = 2*capacity: T* newData = new T[newCapacity]: for (size t i = 0: i < count: ++i) newData[i] = data[i]: delete [] data: data = newData: capacity = newCapacity: assertCcount < capacity): data[count++] = t: void popO { assertCcount > 0): --count; T topO const { assertCcount > 0): return data[count-l]: std::size t SizeO const { return count: }
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0.003
При копировании материалов приветствуются ссылки. |