|
Программирование >> Инициализация объектов класса, структура
----File2.C---- #include QueueLD.h void ReadIn( Queue<LongDouble> * ); int main() { используется определение специализации для Queue<LongDouble> Queue<LongDouble> *qld = new Queue<LongDouble>; ReadIn( qld ); ... Эта программа некорректна, хотя большинство компиляторов ошибку не обнаружат: заголовочный файл QueueLD.h следует включать во все файлы, где используется Queue<LongDouble>, причем до первого использования. 16.10. Частичные специализации шаблонов классов A Если у шаблона класса есть несколько параметров, то можно специализировать его только для одного или нескольких аргументов, оставляя другие неспециализированными. Иными словами, допустимо написать шаблон, соответствующий общему во всем, кроме тех параметров, вместо которых подставлены фактические типы или значения. Такой механизм носит название частичной специализации шаблона класса. Она может понадобиться при определении реализации, более подходящей для конкретного набора аргументов. Рассмотрим шаблон класса Screen, введенный в разделе 16.2. Частичная специализации template <int hi, int wid> class Screen { ... частичная специализация шаблона класса Screen template <int hi> class Screen<hi, 80> { public: Screen(); ... private: string screen; string::size type cursor; short height; для экранов с 80 колонками использтся специальнхе алгоритме! Screen<hi, 80> дает более эффективную реализацию для экранов с 80 столбцами: Частичная специализация шаблона класса - это шаблон, и ее определение похоже на определение шаблона. Оно начинается с ключевого слова template, за которым следует список параметров, заключенный в угловые скобки. Список параметров здесь отличается от соответствующего списка параметров общего шаблона. Для частичной специализации шаблона Screen есть только один параметр-константа hi, поскольку значение второго конструктор для частичной специазации Screen<hi,80> template <int hi> Screen<hi,80>::Screen() : height( hi ), cursor( 0 ), screen( hi * 80, bk ) должен быть определен свой конструктор: { } Если для конкретизации некоторого класса применяется частичная специализация, то определение конструктора из общего шаблона не используется даже тогда, когда определение конструктора Screen<hi,80> отсутствует. 16.11. Разрешение имен в шаблонах классов A При обсуждении разрешения имен в шаблонах функций (см. раздел 10.9) мы уже говорили о том, что этот процесс выполняется в два шага. Так же разрешаются имена и в определениях шаблонов классов и их членов. Каждый шаг относится к разным видам имен: первый - к тем, которые имеют один и тот же смысл во всех экземплярах шаблона, а второй - к тем, которые потенциально могут иметь разный смысл в разных экземплярах. Рассмотрим несколько примеров, где используется функция-член remove() шаблона класса Queue: аргумента равно 80, т.е. в данном списке нредставлены только те параметры, для которых фактические аргументы еще неизвестны. Имя частичной специализации совпадает с именем того общего шаблона, которому она соответствует, в нашем случае Screen. Однако за ее именем всегда следует список аргументов. В примере выше этот список выглядит как <hi,80>. Поскольку значение аргумента для первого параметра шаблона неизвестно, то на этом месте в списке стоит имя параметра шаблона; вторым же аргументом является значение 80, которым частично специализирован шаблон. Частичная специализация шаблона класса неявно конкретизируется при использовании в программе. В следующем примере частичная специализация конкретизируется аргументом шаблона 24 вместо hi: Screen<24,80> hp2621; Обратите внимание, что экземпляр Screen<24,80> может быть конкретизирован не только из частично специализированного, но и из общего шаблона. Почему же тогда компилятор остановился именно на частичной специализации? Если для шаблона класса объявлены частичные специализации, компилятор выбирает то определение, которое является наиболее специализированным для заданных аргументов. Если же ни одно из них не подходит, используется общее определение шаблона. Например, при конкретизации экземпляра Screen<40,132> соответствующей аргументам шаблона специализации нет. Наш вариант применяется только для конкретизации типа Screen с 80 колонками. Определение частичной специализации не связано с определением общего шаблона. У него может быть совершенно другой набор членов, а также собственные определения функций-членов, статических членов и вложенных типов. Содержащиеся в общем шаблоне определения членов никогда не употребляются для конкретизации членов его частичной специализации. Например, для частичной специализации Screen<hi,80> Queue.h: #include <iostream> #include <cstdlib> определение класса Queue template <class Type> Type Queue<Type>::remove() { if ( is empty() ) { cerr << remove() вызвана для пустой очереди\n ; exit(-1); QueueItem<Type> *pt = front; front = front->next; Type retval = pt->item; delete pt; cout << удалено значение: ; cout << retval << endl; return retval; В выражении cout << retval << endl; переменная retval имеет тип Type, и ее фактический тип неизвестен до конкретизации функции-члена remove(). То, какой оператор operator () будет выбран, зависит от фактического типа retval, подставленного вместо Type. При разн1х конкретизациях remove() могут вызываться разные operator (). Поэтому mi говорим, что выбранный оператор в1вода зависит от параметра шаблона. Однако для вызова функции exit() ситуация иная. Ее фактическим аргументом является литерал, значение которого одинаково при всех конкретизациях remove() . Поскольку при обращении к функции не используются аргументы, типы которых зависят от параметра шаблона Type, гарантируется, что всегда будет вызываться exit() , объявленная в заголовочном файле cstdlib. По той же причине в выражении cout << удалено значение: ; всегда вызывается глобальный оператор ostream& operator<<( ostream &, const char * ); Аргумент удалено значение: - это C-строка символов, и ее тип не зависит от параметра шаблона Type. Поэтому в любом конкретизированном экземпляре remove() употребление operator<<() имеет одинаковый смысл. Один и тот же смысл во всех конкретизациях шаблона имеют те конструкции, которые не зависят от параметров шаблона. Таким образом, два шага разрешения имени в определениях шаблонов классов или их членов состоят в следующем: Имена, не зависящие от параметров шаблона, разрешаются во время его определения.
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0.001
При копировании материалов приветствуются ссылки. |