Бьерн Страуструп. Язык программирования С++. Специальное издание (2011) (1004033), страница 84
Текст из файла (страница 84)
Конкретизация шаблона (1егпр!а1е 1пвтапт)ат(оп) Процесс генерации объявления класса по классовому шаблону и его параметру типа называют конкретизацией шаблона (гетр(аге иигопяа(юн) (ВС.!3.7)). Аналогично, конкретная функция генерируется из шаблона функции и заданного значения для параметра типа. Явно определенные программистом версии шаблона для специфических значений параметров типа называются слециализациями (зрес)а))еаВолз).
Компилятор автоматически генерирует все конкретные версии функций (так что это не является заботой программиста) для любого набора конкретных значений параметров типа (ВС.)3.7). Например: Лепна<айаг> сз; гоЫ Т() ( Вгппа<.Тайас> )з; Се= ГКаной нод сгенерировать, решает комнилатор"; ) Здесь компилятор генерирует типы Бзг(на<айаг>, йг(пд<Уейаг> и соответствующие им Веер типы, код для их деструкторов, умолчательных конструкторов и для операции присваивания Яггзпя<сйаг>:: орегазог= (сйаг*) . Так как остальные функции-члены здесь не используются, то их код и не генерируется.
Сгенерированные классы являются совершенно обычными классами, подчиняющимися всем правилам, имеющим отношение к классам вообще. Аналогично, сгенерированные функции подчиняются всем правилам, относящимся к функциям вообще. Очевидно, что шаблоны обеспечивают мощный способ генерации кода из относительно небольших определений. Поэтому требуется некоторая осторожность во избежание перегрузки памяти множеством почти идентичных определений функций (з)3.5). 13.2.3.
Параметры шаблонов Шаблоны могут иметь параметры типа, параметры обычных фиксированных типов (например, знг) и шаблонные параметры ЦС.13.3). Естественно, что один шаблон может иметь несколько параметров. Например: гетр(осе<с)азз Т, Т деТ га1> с!азз Соаз(7* ... *у ); Из приведенного примера видно, что параметр типа может использоваться для объявления последующих параметров шаблона. Аргументы целого типа очень удобны для задания размеров и границ. Например: гетр!иге<с(азз т, !пг тах> с(азз ВиДег Тг(тах]; Встречающийся в литературе термин инстаниирование труден для произношения.
— Прим. ред. ) 3.2. Простой шаблон строк 407 риЫ(с: Ви()ег() ( ) 11,., ): Вийег<сйаг, 128> сЬи1; Ви()гег<(л(, 5000> (Ьиу;. ВиЯег<Весог4, 8> гЬиу; Простые, ограниченные контейнеры, вроде ВиКег, полезны в задачах, требующих высочайшей эффективности и компактности кода (так что там не подходят универсальные контейнеры типа е(г(л8 и гес(ог). Передача размера в виде аргумента шаблона Визг позволяет избежать затратных операций динамического выделения свободной памяти. Другим примером может послужить тип ЯалВе из В25.б.1. Аргумент шаблона может быть константным выражением ЯС.5), адресом объекта или функции с внешней компоновкой (59.2)г или указателем на член класса (В!5.5). Указатель, используемый в качестве аргумента шаблона, должен иметь форму ао1; где о/' — это имя объекта или функции; или же иметь форму 1: где 1'— это имя функции.
Указатель на член класса должен быть в форме ьХ:: о1", где о1'— имя члена. Строковые литералы в качестве аргументов шаблонов не допускаются. Целый аргумент шаблона должен быть константой: гой(1'( 1п( () ВиЯег<1л(, (> Ьх( ,((еп ог.' н(ребуется констанп(ное выражение Параметр шаблона, не являющийся типом, в теле шаблона является константой, так что попытка изменить его трактуется как ошибка. 13.2.4. Эквивапентностьтипов Располагая шаблоном, мы можем генерировать конкретные типы, предоставляя конкретные значения для аргументов шаблона. Например: Яппя<сйаг> я1; Яппя<ипв18пе(( сйаг> е2; Вгг(пя<(п(> в5( (уре((е1 ипв18пе(( сйаг Г(айаг( Б(пп8<((айаг> я4; Я(г(ля<айаг> в5( ВиЯег<5(пня<айаг>, 10> Ы( ВиВег<сйаг, 10> Ь2; Вибег<сйаг, 20 — 10> ЬЗ; Предоставляя один и тот же набор аргументов шаблона, мы имеем дело с одним и тем же сгенерированным типом.
Но что в данном контексте означает «один и тот же»? Так как (уре()еГ не создает нового типа, то В(г(л8< Е(сйаг> есть то же самое, что и Яг(л8<иле18ле(( айаг>. И наоборот, так как с))аг и цпз(лпес) с)(аг суть разные типы (В4.3), то и типы Я~г(л8<сйаг> и ЯП(л8<лле18леИ сйаг> тоже разные. Компилятор может вычислять константные выражения, поэтому тип Ви1"- 1ег<сйаг, 20-10> эквивалентен типу Вийег<сйаг, 10>. Глава ) 3. Шаблоны дов 13.2.5.
Проверка типов Шаблоны определяются и впоследствии используются в комбинации с набором аргументов шаблона. В определении шаблона можно обнаружить ошибки, не связанные непосредственно с возможными конкретными значениями аргументов шаблона. Например; гетрйае<сйгзз Т» сйззз Пп ( ягисг Ппй ( Лией* рге; Пай* зис; Т гагг Ппь(ПпЬ* р, 1лп1с' л, сопле Ть г): рге(р), зис(з), иИ(г) (1 1 Призах еггог: отсутствует тонна с затопай риЬЬс: ПпЬ(): Ьеад(7) () П еп ог: уколите«ь инициолиз-сл тонии (п( ЕЫ (сопл( Ть г): Ьеад(пот 1лпЬ (О, о, г) ) ( ) У еггоп неопределенный идентификатор 'о' П... гоЫ рига ад и сонм (Гог (1лпЬ* р = Ьеад; р; р=р-' зис) соил«р->га1« ' ~п '; ) )' Компилятор в состоянии распознать простые семантические ошибки в точке определения или позднее в точке использования.
Пользователи предпочли бы более раннее выявление ошибок, но не все такие «простые» ошибки легко обнаружить. В примере выше я сделал три «ошибки». Совершенно независимо от того, что есть параметр шаблона, указатель типа ПпЬ* не может инициализироваться целым значением 7.
Аналогично, идентификатор о (опечатка — должен был быть нуль) не может быть аргументом конструктора Т1м< Т>:; Х)пЬ, поскольку в доступной области видимости такого имени нет. Любое имя, используемое в определении шаблона, должно либо входить в его область видимости, либо очевидным образом зависеть от параметра шаблона (8С.!3.8.1). Наиболее очевидными формами зависимости от параметра шаблона Тявляется объявление члена типа Тили функции-члена с аргументом типа Т. Более тонким примером служит выражение соиг«р->га1 в функции-члене Пзг<Т»::ргшг аПО. Ошибки, имеющие отношение к использованию конкретных значений параметров шаблонов, нельзя обнаружить до момента конкретизации шаблона.
Например: сгазз Пес ( l* ... *l 1; гой$ Т(сопле Пег<(пг»ь Н, сопи Ь!ее<Пес> ь 1г) П.ринг аП(); 1г.рппг аП() г ) Здесь выражение П.рг1пг аП() вполне корректно, но выражение 1г.рг1пг аП() порождает сообщение об ошибке использования типа, ибо операция вывода «не определена для типа Пес. Самой ранней точкой обнаружения ошибок, связанных 13,3.
Шаблоны функций 409 с параметрами шаблонов, является точка первого указания конкретного типа для параметра шаблона. Такую точку программы принято называть первой точкой конкретизации шаблона или просто точкой конкретизоу(ии шаблона (роту о]' тиуопйоуюп) (см. 9С.13.7). Однако в реальных системах разработки (включаюших компиляторы) проверки подобного рода могут откладываться до этапа компоновки. Если бы в представленной выше единице трансляции находилось лишь объявление функции рейну аУУ(), а не ее определение, то проверка соответствия типов могла быть отложена до более поздних этапов (5! 3.7). Независимо от того, на каком этапе производится проверка, применяемые для ее выполнения правила одни и те же. Естественно, что для пользователей более ранние проверки предпочтительны. Можно наложить ограничения на допустимые аргументы шаблонов посредством функций-членов (513.9[161).
13.3. Шаблоны функций Для большинства людей самым первым и очевидным применением шаблонов является определение или использование таких контейнеров, как Ьаи!с иггипд ($20.3), иесуог (э16.3), уаг (э!7.2.2) и тар (517.4.1). Сразу за этим возникает потребность в шаблонных функциях. Сортировка массивов иллюстрирует сказанное: гетр(осе<с(от Т> гоЫ ион(гесуог<Т>и) у йобъяеление гоЫ](иесиог<т(>ь и, иесуог<иугупа>и т) ( логу (и); Ю иог((нес(ог<уп( &); логу (ии) у й иогг(нес(ог<ио ЫК> &); ) (етруауе<суаии Т> гоЫ иог((гесюг< Т> и и) (( определение У ЯЬе(У иог( (Кпи(Ь, )'о!. 3, рк.
84). ( сопи иуие и и = и. Ыие (); ]ос(ту дар=и/2( 0<кар; яар у= 2) ]ог(ипи (=пар; у<п; у-~+) ]ос(упи]=у-Кару 0<=(; / -= яар) у](г(увдар) <г(у)) ( Т(етр = и(у1; и(у) =г(]~гдар) у и (]+Кар) = гетр; ) еае Ьгеаа; ((инар и(у] и ~Я+Кар] Когда шаблонная функция вызывается, типы фактических аргументов вызова определяют, какая конкретная версия функционального шаблона используется— аргументы шаблона выводятся (бес(исед) из типов аргументов функционального вызова (513.3.1).