Д. Вандевурд, Н.М. Джосаттис - Шаблоны C++. Справочник разработчика (2003) (1160769), страница 54
Текст из файла (страница 54)
Более подробно этот вопрос изложен в разделе 16.1, стр. 311. В главе 13, "Направления дальнейшего развития", обсуждаются некоторые возможные будущие свойства шаблонов, которые способны упростить этот аспект разработки шаблонов. 15.1.8. Накопление с обобщенными итераторами Прежде чем закончить введение в свойства и стратегии, полезно рассмотреть еще одну версию ассша(), которая позволяет работать с обобщенными итераторами вместо указателей, что и ожидается от обобщенного промышленного компонента.
Интересно, что возможность вызова ассша() с указателями при этом остается, поскольку стандартная библиотека С++ обеспечивает использование так называемых свойств иеепалюров (нега(ог )га!Сз). Для этого можно переписать начальную версию ассунт() (опускаем при этом последующие усовершенствования).
// СгаТСв/ассшво.)зрр ()1гпс)еТ АСС()Н НРР ()с)ейхпе АСС(дя НРР ()1пс1ис)е <ТСегасог> Сеазр1аСе <Сурепазае 1Сег> Тп11пе Сурепке вМ::ТСегаСог Сгахгв<1Сег>::ча1ие Суре асспза(ТСег вгагС, 1Сег епс)) ( Суредей Сурепаазе вСЙ::Тсегасог Сгайсв<1Сег>::ча1пе Суре ЧТ; ЧТ соса1 = ЧТ(); // предполагаем, что ЧТ()создает // нулевое значение ыМ1е (вгагС )= епс)) Глава 15. Классы свойств и стратегий 290 тота1 += *зтагт; ++зтагТ; ) геТпгп ТоТа1; вепйН // АСС\Ж НРР Структура 1тегатог тгайтя инкапсулирует все существенные свойства итератора.
Благодаря наличию частичной специализации для указателей эти свойства могут использоваться для любых обычных указателей. Ниже показано, как стандартная библиотека может реализовать эту поддержку. павеярасе зТй ( Тевр1аТе <Турепаве Т> зТгпсТ 1ТегаТог Тга1Тя<Т*> ( Турейей Т Турейеб рггй1йй Т Турейей гапйов ассеяя 1Тегагог Тад Турейей Т* Турейеб Та ча1пе Туре; й1ййегепсе Туре; 1Тегасог саседогу; ро1псег; гейегепсе; ): ) Однако типа для накопления значений, к которым обращается итератор, здесь нет, так что нам придется разрабатывать свой собственный класс Ассов п1аТ з.опТга1Тз.
15.2. Функции типа в1пс1пйе <яТййей.)з> $1пс1пйе <1ояТгеав> В первоначальном примере использования свойств показано, что можно задавать поведение, зависящее от типов. Это отличается от того, что мы обычно делаем в программах. В языках программирования С и С++ функции более точно можно назвать функ. циями значения (на!ае (опсйопз): они принимают одни значения в качестве параметров н возвращают другое значение в качестве результата. При работе с шаблонами мы сталкиваемся с функциями вина (1уре Гнпсйопз), т.е.
функциями, которые принимают некоторые аргументы типа и возвращают тип или константу в качестве результата. Весьма полезной встроенной функцией типа является з1кеой, которая возвращает константу, указывающую размер (в байтах) данного аргумента типа. Шаблоны классов также могут играть роль функций типа. Параметры функции типа — это параметры шаблона, а результат получается как тнп-член или константа-член. Например, оператор я1кеой может быть использован с приведенным ниже интерфейсом.
// Тга1Тз/з1кеой.срр 15.2. Функции типа 291 сешр1аге <Еурепаше Т> с1авв ТуреЯ1ге ( рцЫ1с: всаг1с в1ге Г солне ча1це = в1геой(Т) 1пг ша1п(! ( вМ::соцс « "ТуреЯ1ге<1пе>::ча1це = «ТуреЯ1ге<1пе>::ча1це «вМ::епд1/ ) 15.2.1. Определение типа элемента В качестве другого примера предположим, что у нас есть ряд шаблонов контейнеров: чессог<Т>, 1х ве<Т> и в пас)«Т>. Нам нужна функция типа. которая для данного типа контейнера возвращает тип его элементов.
Этого можно достичь с помощью частичной специализации. // гга1гв/е1ешепгеуре.срр $1пс1цйе <чесгог> М1пс1цс(е <11ве> ()1пс1цс(е <вгас)с> ()1пс1цс(е <1овсгеаш> $1пс1цс)е <гуре1пго> Гешр1асе <Гурепаше Т> с1авв Е1ешепГТ; // Первичный шаблон Гешр1асе <Гурепаше Т> с1авв Е1ешепГТ<вгд::чессог<Т» ( // Частичная специализация рцЫ1с: куреней Т Туре; Гешр1аее <Сурепаше Т> с1авв Е1ешепГТ<вей::11зг<Т» ( РцЫ1 с: Гуре<(ей Т Туре; ); // Частичная 'специализация Сешр1асе <Еурепаше Т> В дальнейшем рассмотрим несколько более универсальных функций типа, которые могут использоваться а качестве свойств.
Глава 15. Классы свойств и стратегий 292 с1авв е1еаепст<всс)::всас)с<т» ( // частичная специализация райс: сурес)ей Т Туре( СЕар1асЕ <сурЕПааЕ Т> чойс) ргйпк е1еаепт Суре (Т сопве а с) ( вас)::соцк « "Сопкайпек ой «сурейс)(сурепаве Е1евепсТ<Т>::Туре) .паве() « " е1евепсв.~п"; Тпс аайп() ( вес)::всасК<Ъоо1> в; ргйпс е1евепс суре(в) Использование частичной специализации позволяет реааповать эту функцию, не требуя, чтобы в типы контейнера были заложены сведения о ней. Зачастую, однако, функция типа разрабатывается вместе с соответствующими типами, так что ее реализация может быть существенно упрощена.
Например, если типы контейнера определаот тип элемента ча1ие суре (как это делают стандартные контейнеры), то можно написать следующее: сеар1асе <сурепаве С> с1авв Е1евепСТ ( рцЪ11 с: суре<)ей сурепаве С::ча1це Суре Туре; Этот код может быть реализацией по умолчанию, что не исключает наличия специализаций для тех типов контейнеров, для которых не задан соответствующий тип элемента ча1ие суре. Тем не менее обычно желательно обеспечить возможность определения типов для параметров шаблонов, чтобы к ним было легче обращаться в обобщенном коде.
В следующем далее фрагменте кода представлен набросок этой идеи. севр1асе <сурепаае т1, сурепаае т2, ... > с1авв Х ( РЦЫТс $ Суре<)ей Т1 Сурес)ей Т2 В чем заключается польза функции типа? Она позволяет параметризовать шабло~ в терминах типа контейнера, не требуя при этом дополнительных параметров для типа элемента и других характеристик.
Например, вместо 15.2. Функции типа 293 Гевр1асе <Гурепаве Т, сурепаве С> Т зша об е1евепгз(С сопзга с); (где требуется указание типа элемента в явном виде при помощи синтаксиса зша ой е1евепгз<1пс>(11зс)) можно обьявить севр1асе<гурепаве С> сурепаве е1евепгт<с>::туре зив,ой е1евепсз(С сопзгй с) (где тип элемента определяется функцией типа).
Обратите внимание, что свойства могут быть реализованы как расширения существующих типов. Таким образом, функции типа можно определять даже для фундаментальных типов и типов из закрытых библиотек. В данном случае тнп Е1евепст назван свойством, поскольку он используется для обращения к свойствам типа данного контейнера С (в общем случае в таком классе может быть собрано несколько свойств).
Таким образом, классы свойств не ограничиваются описанием лишь характеристик параметров контейнера, но могут использоваться для описания любого вида "основных параметров". 15.2.2. Определение типов классов С помощью приведенной ниже функции типа можно определить, является ли тип классом. // ггаусз/Тзс1аззс.)зрр Севр1асе<сурепаве Т> с1азз 1зС1аззТ ( ргйчаге: сурес)ей с)заг Опе; Гурес)ей вегас (с)заг а[2]; ) Тмо; Гевр1аге<сурепаве С> зсасйс Опе Сепг(тпс С::*); Гевр1асе<сурепаве С> зсасйс Тмо Гезс(...); риЫ1с: епшп ( Уез = зйхеоб(1зС1аззТ<Т>::Сезг<Т>(0) ) == 1 епша ( Бо = !уез ); Этот шаблон использует принцип ЗНХАЕ, который рассматривается в разделе 8.3.1, стР 129.
Принцип функционирования БН(чАЕ состоит в поиске конструкции типа, котоРая является недопустимой для типов функций (но не для других типов), или наоборот. для типов классов можно использовать то, что такая конструкция типа, как указатель на член Тпг с:: *, правомерна только в том случае, если с является классом. Представленная далее программа использует эту функцию типа для проверки того, являются ли некоторые типы и объекты классами. // Сгаегз/Тзс1аззг.срр Глава 15.
Классы свойств и стратегий 294 ()Тпс1цс)е <Тозггеаш> ()Тпс1цс)е "Твс1аввс.)трр" с1азв МуС1авз ); вггцсг МуЯГгцсс ( цпфоп МуУпТоп ( ); чоЫ шуйцпс() ( ) епцш Е ( е1 ) е; // Проверка путем передачи типа в качестве аргумента шаблона сешр1асе <гурепаше т> чоЫ сйес)<И Ы (1зС1авзТ<Т>:суев) ( зад::соцг « " ХвС1авзТ " « вас)::еп61; ) е1ве ( вас)::соцг « " 11зС1авзТ " «вами::епс)1; ) // Проверка путем передачи типа в качестве аргумента функции Гешр1асе <Сурепаше Т> чойс) сйесКТ(Т) ( с)тесК<Т>() Тпг шайп() ( вас):: с « "'пг: сЬес)с<1пс>(); вас)::соцг « "МуС1авв: с)тесК<МуС1авв>(); все)::соцс « "МуЯсгцсг:"; Мувегцсе в; (5.2.
Функции типа 295 с)тесКТ(в)! вес)::соус « "Му()п1оп: с)тесК<му()п1оп>()! вой::соус « "епша: с)тесКТ(е)! згс)::сонг "а!уйппс() с)тесКТ(л!уйипс)! Программа дает следующий вывод: 15.2.3. Ссылки и квалификаторы Рассмотрим определение шаблона функции // ага'Гв/арр1у1.)трр Гешр1асе <куренное Т> чоЫ арр1у(Та агд, чоЫ (*йипс)(Т)) ( Гипс (агд)! ) н код, который пытается его использовать: // сгассв/арр1у1.срр ()1пс1ис)е <1овсгеаш> вйпс1пс)е "арр1у1.)трр" чоЫ Тпсг(йпга а) ( уоЫ ргйпе(1пс а) згс);:соне « а « зсй::епс)1! ) 1пс: МуС1авв: муясгисг: му()п1оп: епша: туйппс (): ! ТвС1азвТ 1вС1аввТ 1зС1аввТ 1вС1аввТ )1вС1аввТ !1вС1аввТ Глава )5.
Классы свойств и стратегий 296 йпг шаз.п(] йпг х = 7з арр1у(х, ргйпс); арр1у(х, йпсг); // сгайгв/гуреор1.)зрр Сешр1асе <Гурепаше Т> с1авв ТуреОр рцЬ1з.с: Сурег)ей Т Сурес)ей Т курек)ей Т сопев Гурег)ей Т й курек)ей т * гурес)ей т сопвг и // Первичный шаблон Агдт; ВагеТ; Сопвст; Кейт; КейВагеТ! КейСопвгт; Сначала разработаем частичную специализацию для типов с описанием сопев.