Д. Вандевурд, Н.М. Джосаттис - Шаблоны C++. Справочник разработчика (2003) (1160769), страница 43
Текст из файла (страница 43)
Рассмотрим снова наш список обобщенного шаблона ь1вс (обьявленный в точке (1)). Мы уже рассматривали о"тимизжию списка указателей. Но у нас может возникнул желание сделать то же самое и с определеннымн типами "указатель на член". Ниже приведен код, который оптимизирует список для указателей на указатель на член. 228 Глава 12. Специализация и перегрузка Сешр1аее<еурепаше С> с1азв 1.1ве<чоЫ* С::*> ( // (4] риЬ11с: // Частичная специализация для любого члена // типа указатель на чоЫ* // Любой иной тип указателя на указатель на член // будет использовать ее куреней чоЫ* С::*Е1ешепСТурег чойб аррепс)(Е1ешепСТуре рш); 1п11пе вйае С 1епдс)з(] сопвс; Сешр1ате<турепаше Т, Сурепаше С> с1авв Ьйве<Т* С::*> ( // (5) рг1часе: Ейве<чоЫ* С::*> ыар1; рц)э11с: // Частичная специализация для любого типа // указателя на указатель на член, за // исключением члена типа указателя на чоЫ*, // который обработан ранее.
Заметим, что у этой // частичной специализации два шаблонных параметра, // тогда как у первичного шаблона — только один сурес)ей Т* С: ь*Е1ешепсТуре; чоЫ аррепс)(Е1ешепСТуре рш) ( Тшр1.аррепд((чоЫ* С::*)рш); ) 1п11пе вйае с 1епдсЬ() сопвс ( гесцгп 1шр1.1епдс)з(); ) В дополнение к замечаниям относительно числа шаблонных параметров отметим, что общая реализация, определенная в точке (4), которую используют все остальные объекты (из объявления в точке (5)), сама является частичной специализацией (лля случая простого указателя — это полная специализация). Однако очевидно, что специализация в точке (4) более специализирована, чем в точке (5), так что неоднозначности не возникает. 12.5.
Заключение 229 12.5. Заключение Полная специализация шаблона была частью механизма шаблонов С++ с самого начала. Перегрузка шаблона функции и частичная специализация шаблона класса появились значительно позже. Компилятор НР аС++ стал первым компилятором, ревлнзовавшим перегрузку шаблона функции, а ЕООСн первым реализовал частичную специализацию шаблона класса Пряящипы частичного упорядочения, описанные в этой главе, первоначально были разработаны Стивом Адамчнком (31ече Адашеву(с) и Джоном Спайсером (1оЬп Яр(сег) (оба из НЗО).
Ваиюжность применения акцнапюаций шаблонов дяя завершения рекурсивного шаблонного определения (явк в примере с 1 Твс<т*>, приведенном в разделе 12.4) известна уже давно. Однако Эрвин Аирух (Егейп ()пгц(з), вероятно, первый заметил, что это приводит к интересной концепции шаблонного металрограммирования: использование механизма инстанцирования шаблонов для выполнения нетривиальных вычислений во время компиляции. Данной теме посвящена глава 17, "Метапрограммы". Возникает вполне резонный вопрос: почему частично специализировать можно только шаблоны классов? Причины этого в основном исторические.
Можно определить такой же механизм и для шаблонов функций (см. главу 13, "Направления дальнейшего развития"). В ряде аспектов тот же эффект достигается путем перегрузки шаблонов функций, но здесь есть и некоторые тонкие отличия, в основном связанные с тем, что при использовании этого механизма осуществляется поиск только первичного шаблона.
Специализации рассматриваются впоследствии, для определения того, какая именно реализация должна использоваться. В отличие от этого все перегруженные шаблоны функций должны вноситься в набор перегрузки для выполнения поиска; при этом они могут находиться в различных пространствах имен или классах. Это несколько увеличивает вероятность непреднамеренной перегрузки имени шаблона С другой стороны, можно представить возможность перегрузки шаблонов классов, например: l/ Некорректная перегрузка шаблонов класса сегар1асе<сурепазае Т1, сурепке Т2> с1авв Райк; севр1асе<йпс ы1, Тпс Н2> с1авв Райт; Однако насущной необходимости использования такого механизма не видно.
Глава 13 Направления дальнейшего развития Шаблоны языка С++ прошли значительный пуп, развитиа — от своего появления в 1988 году и до стандартизации языка С++ в 1998 году (техническая работа была завершена в ноябре 1997 года). Затем в течение нескольких лет определения языка оставались стабильными, но за это время появился ряд новых потребностей, связанных с шаблонами С++. Некоторые из них были вызваны желанием иметь менее противоречивый и более формальный язык. Почему, например, в шаблонах функций не разрешены аргуменпа шаблона, используемые по умолчанию, если они разрешены в шаблонах классов? Подсказкой для других расширений языка служит все возрастающая сложность программных идиом шаблонов, балансирующая на грани возможностей существующих компиляторов. Ниже опнсывакпся некоторые расширения, наиболее часто используемые разработчиками языка С++ и его компиляторов.
Многие нз этих расширений были подсказаны разработчиками различных библиотек языка С++ (включая стандартную). Нет никаких гарантий, по когданибудь они стануг частью стандартного языка С++. С другой стороны, некоторые нз них уже вылечены в определенные реализации языка С++ в качестве расширений. 13.1.
Коррекция угловых скобок Для начинающих программировать шаблоны довольно часто неожиданностью оказывается то, что между двумя последовательными закрывающими угловыми скобками необходимо вставлять пробел. Например: Фйпс1ис1е <11вк» ййпс1пс)е <чессок> сурес1ей всей: гцессот<всс)::11вс<1пс» ьйпетаь1е1 // пРАВильнО суре<)ей вас)::згессог<всб::11вп<йпк» Ос)тектаь1ез // ОшиБкА Второе объявление суребей содержит ошибку, так как две закрывающие угловые скобки без пробела между ними представляют собой операцию "сдвиг вправо" (»), которая в данном месте исходного кода не имеет никакого смысла. Ситуация, когда компилятор обнаруживает данную ошибку и молча трактует операцию» как две ~~крывающие угловые скобки (эту особенность иногда называют кор- Глава 13.
Направления дальнейшего развития 232 рекцией угловых скобок), относительно проста по сравнению со многими другими осо бенностями синтаксических анализаторов исходного кода на С++. Действительно, многие компиляторы способны распознавать такие ситуации и принимают некорректный код, выдавая при этом только предупреждающее сообщение. Поэтому вполне вероятно, что в будущей версии языка С++ обьявление для Ох)хехТа)з1е (из предыдущего примера) будет считаться действительным. Тем не менее следует отметить, что существует ряд тонких нюансов, связанных с коррекцией угловых скобок.
На самом деле встречаются ситуации, когда операция» является действительной лексемой в списке аргументов шаблона. Эго иллюстрирует приведенный ниже пример. Вешр1ахе<хпх М> с1авв Впб; Сешр1асе<сурепаше Т> чохе) вхгапде() () сешр1асе<хпс м> чей всхапде() () Тпс льзхп() ( вххапде<Вий<1б»2»(); // » не является ошибкой ) В какой-то степени к рассматриваемой проблеме имеет отношение вопрос о случайном использовании диграфа <:, который эквивалентен квадратной скобке [ (см. раздел 9.3.1, стр. 152). Рассмотрим следующий фрагмент кода: сешр1асе<хурепаше т> с1авв ьхвсз с1авв Мах)<екз Ьхвх<::Маг)<ех>* шах)сехв; //ОШИБКА Последняя строка в данном примере трактуется как Ьхвс(:Мах)хек>* шах)сехв;,что вообще не имеет никакого смысла Однако компилятор мог бы, вероятно, принять во внимание то, что за таким шаблоном, как 1Л.вс, не может следовать левая (открывающая) квадратная скобка, и в данном контексте не трактовать дпраф <: как квадратную скобку.
13.2. Менее строгие правила использования ключевого слова 1урепыпе Некоторые программисты и разработчики язьжа находят правила применения ключевого слова Гурепаше (см. разделы 5.1, стр. 65, и 9.3.2, стр. 154) слишком строгими. Например, в приведенном далее коде в хурепщае Ахгау<т>:: е1ешепхт присухствие этого ключевого слова обязательно, а в сурепщае Актау<хпс>:: е1елюпст — запрещено. Сешр1асе <Сурепахае Т> с1авв Актау ри)э1з.с: Хуредеб Т Е1ел|епСТ; ) З.З. Аргументы шаблонов функций по умолчанию 233 Севр1асе <Гурепаве Т> чоЫ с1еаг(еурепаве Аггау<Т>::Е1евепГТй р)з // ПРАВИЛЬНО севр1аге<> чоЫ с1еаг(сурепаве Аггау<1пс>::Е1евепГТй р); // ОШИБКА Такие примеры, как этот, могут быть несколько неожиданными, а поскольку в реализации компилятора языка С++ нетрудно игнорировать лишнее ключевое слово, разработчики языка думают о том, чтобы допустить постановку ключевого слова гурепаве перед любым полным именем типа, если только оно уже не дополнено одним из ключевых слов нггисс, с1аее, ип1оп или епив.