А. Александреску - Современное проектирование на C++ (1119444), страница 15
Текст из файла (страница 15)
с1аав ьц11туреО," Обычно объекты этого класса не создаются. Его единственное прелназначение — обозначить типы, не представляющие интереса. В разделе 2ДО класс нц1)туре используется в ситуациях„когда тип имеет синтаксическиЙ смысл, но не имеет семантического. (Например: "На объекты какого типа указывает переменная типа опт?".) Кроме того, списки типов, описанные в главе 3, используют класс ни11туре в качестве маркера конца списка и лля возврата сообщения "тип не найден". Второй вспомогательный тип — класс впртутуре.
Как и следовало ожидать, его определение имеет следуюгпий вид. зтгцст яертутуре ()' Этот тип можно использовать в качестве базового класса, а также для передачи значений типа вврсутуре. Кроме того, его можно применять в шаблонах в качестве типа, заданного по умолчанию ("не важно какой"). 2.10. Характеристики типов Характеристики (пава) — это метол обобщенного программирования, позволяющий принимать решения на этапе компиляции программы, основываясь на информации о типах, аналогично тому, как в ходе выполнения программы принимаются решения, основанные на значениях (Л)ехапдгезсц, 2000а).
Предоставляя "дополнительный окольный путь"', позволягоший решить многие проблемы, связанные с проектированием программного обеспечения, характеристики дают возможность принимать решения. основываясь на информации о типах, находясь вне конкретного контекста. Код, полученный в результате, становится яснее, читабельнее и легче в эксплуатации. Обычно программисты пишут свои собственные характеристические шаблоны и классы для обобщенного кода. Однако характеристики можно применять к любым типам.
Они помогают программисту, создающему обобщенный код, точнее согласовать шаблонный кол с возможностями типа. Допустим, что мы реализуем алгоритм копирования. теер1аге <турепапе тпгт, турепапе оцтгт> Оиттт Сору(тптт Н гзт, 2птт 1азт, Ооттт геьц1т) Фог (; Н гас )= 1авт; ++Я гас, +ьгевц1т) *гевц1т = "Л гас; 61 Глава 2. Привмы программирования Теоретически такой алгоритм реализовывать не имеет смысла, поскольку он дублирует возможности библиотечной функции ятб:: сору. Однако иногда возникает необходимость специально настроить функцию копирования на опрелеленный тип.
Предположим, что мы разрабатываем код для многопроцессорной машины, в которой предусмотрена очень быстрая элементарная функция в1тв1аят. Естественно, мы хотели бы использовать это преимушество там, где это возможно. // прототип функции в(дв1аят в заголовочном файле // "ятмп Рг(ки т(чея.Ь" чеза вздв1аят(сопят чо(б* ягс, чо(6* деят, язхе т Ьутея); Разумеется, функция в(дв1аят предназначена для копирования только элементарных типов и простых старых структур данных, Эту функцию нельзя применять к типам, имеющим нетривиальный конструктор копирования.
Таким образом, желательно было бы реализовать новую функцию Сору так, чтобы использовать преимушества функции вздв1аят с максимальной выгодой и при копировании объектов более сложных типов. При копировании элементарных типов функция сору "совершенно непонятным образом" будет выполняться быстрее. Для того чтобы реализовать функцию Сору, нужно выполнить две проверки. ° Являются ли переменные тптт и оиттт обычными указателями (в отличие от более сложных типов итераторов)? ° Можно ли копировать объекты, на которые ссылаются указатели тптт и питтс, побитово? Если на этапе компиляции мы положительно ответим на оба вопроса, можно применять функцию вздв1аят. В противном случае нужно использовать обобшенный цикл Рог.
Решить такие проблемы можно с помошью характеристик. В этой главе, в основном, используется реализация характеристик из библиотеки Воояс С++ (Воояс). 2. ?0. т. Реализация характеристик указателей В библиотеке (.ой опрелелен шаблонный класс туретгазтя, в котором собрано множество характеристик обобшенных типов. Этот класс специализирует шаблоны, содержащиеся в нем, и представляет результаты. Реализация характеристик большинства типов основывается на полной или частичной специализации шаблонов (раздел 2.2). Например, приведенный ниже фрагмент кода определяет, является ли тип т указателем.
теир1ате <турепаие т> с1аяя туретгазтя ( Ргзчате: теир1ате <с1аяя ц> ятгцст поз'птегтгаз'тя ( епци(геяц1с = Фа1яе ]; туредеУ нц11туре позптеетуре; сеир1ате <с1аяя ц> ясгост позптегтгазтя<ц*> епци ( геяц1с = тгце ); туредеФ ц Розптеетуре; ); рцЬ)зс: епци ( (яро(птег = Ро(псегтгазтя<т>::геяц1т ); 62 Часть Ь Методы суребе1 Рот псе гтга( сэ<т>:: Рот псеетуре Ро( псеетуре; В первом определении вводится шаблонный класс Ро(псегтгатсэ, который как бы говорит: "Класс т — не указатель'*. Напомним, что ранее (в разделе 2.9) в этих ситуациях применялся класс нц11туре.
Во втором определении (выделенном в тексте) вводится частичная специализация шаблонного класса Ро(псегтга(сэ, соответствуюшая любому типу указателей. Для нулевого указателя, который не ссылается ни на один объект, специализация, выделенная в тексте фрагмента, квалифицируется как соответствие, более точное, чем обобшенный шаблон любого типа указателей. Следовательно, вступает в силу специализация для указателей, а переменная гевц1с принимает значение сгце. Класс Рот псеетуре определяется соответствуюшим образом. Теперь можно понять внутреннее устройство реализации класса зсб::чессог::тсегасог — является он простым указателем или представляет собой некий сложный тип? (пс ва(пО сопзс Ь001 (СегтзРСг туретгазтз<честог<зпС>::1Сегатог>::заро(птег; соцс « "чессог<(пс>::1сегасог (з " « (сегсэясг ? 'Таас" : "эвагс" « '~п'; Аналогично в классе туретга(св реализуется константа (эяеТегепсе и опрелеляется тип яеТегепсетуре.
Для ссылочного типа т класс яеРегепсетуре представляет собой тип, на который ссылается объект класса т. Если класс т является обычным типом, то класс яеУегепседтуре совпадает с ним. Разпознавание указателей на члены класса (глава 5) немного отличается от описанного выше. Для этого нужна следуюшая специализация. севр1асе <сурепаве т> с!ада туретгазсэ ( рг(часе: севр1асе <с1аээ ц> эсгисс Ртомтга(сз епцв ( геэц1с = 1а1зе ); севр1асе <с)азз ц, с1ава ч> эсгисс Ртомтга(сз<ц ч::*> ( епцв ( геэо1с = сгце ); риЬ)зс: епцв ( (змевЬегро(псег = Ртомтга(са<т>::гези1с ); 2. 10.2.
Распознаааниа осноаных типоа Класс туретга(сэ<т> реализует статическую константу зэвтбгипбавепса1. По значению этой константы можно определить, является класс т стандартным основным типом или нет. К этим типам относится тип чо(б и все числовые типы (которые, 63 Глава 2. Приемы программирования в свою очередь, подразделяются на типы чисел с плавающей точкой и целочисленные типы).
В классе туретга1тз реализуются коне~виты, показывающие категорию, к которой может принадлежать заданный тип. Немного забегая вперед, следует сказать, что списки типов (глава 3) позволяют легко определять, принадлежит ли тип заданному множеству типов. Пока нам нужно знать лишь то, что приведенное ниже выражение (в котором суффикс пп означает количество типов, перечисленных в списке) возвращает позицию класса т в списке, начиная отсчет от нуля, или число -К если заданного класса в списке нет.
ТС:: кп6ехос<Т, ТЧрЕС15Т пп(снисок типов, разделенны занятыми)>:: ча1ие Например, значение выражения ть::тп6ехоТ<т, тчрвс35Т 4(з(дпе6 сЬаг, зйогт 1пт, 1пт, 1опд 1пт)>::ча1ие больше или равно нулю, только если класс т является целочисленным типом со знаком.
Ниже приведен фрагмент определения класса туретга)т для основных типов. тешр1ате <турепаше т> с1азз туретга1сз ( как показано выше риЫ)с: туре6е~ тчрвс15Т 4( ипз19пе6 сЬаг, ипз19пе6 зЬогт )пт, ипз(9пе6 1пт, ипз19пе6 1оп9 )пт) ипз(дпе6тптз; туре6еТ тчрвствт 4(519пе6 сЬаг, зЬогг 1пт, 1пг, 1опд (пт) 5(дпе61птз; туре6е1 тчрвьт5т 3(Ьоо1, сйаг, чвсйаг т) Отйегтптз; туре6еТ тчрвьт5т 3(Воат, 6оиЫе, 1опд 6оиЫе) р1оагз; епиш ( 155т6ипзздпе6тпс = тс:свп6ехо~<т, ипз1дпе6тптз>::ча1ие >= О ); епиш ( 455т6519пе61пт = тс:свп6ехО~<т, 51дпе63птз>::ча1ие >= О ); епиш ( 155т63птедга1 = 155тбипз)дпе63пт ~! зз5т65)дпе6тпт !! ТС::тп6ехо~<Т, Отйегтптз>::ча1ие >= О ); епиш ( 155с6г1оат = ть::тп6ехо1<т, р1оатв>::ча1ие >= О ) епиш ( 355г6дг)ТЬ = з'55т6тпседга1 !~ 155т6р1оат ); епиш ( 355т6рипбашепта1 = 355т6дг1ТЬ П 455т6р1оат ~! Сопчег51оп<т, чо(6>..зашеТуре ); Использование списков и класса тс::тп6ехо~ дает возможность быстро получать информацию о типах, не прибегая к многократной специализации шаблонов.
Если вы не можете устоять перед соблазном покопаться в деталях, можете сразу перейти к главе 3, но не забудьте вернуться обратно. Фактическая реализация процедуры распознавания основных типов намного сложнее, что позволяет применять ее для распознавания более широкого спектра классов, разрабатываемых производителями программного обеспечения (например, (птб4 или 1опд 1опд). 2. 10.3. Оптимальные типы параметров В шаблонном коде иногда нужно ответить на следующий вопрос.
Задан произвольный тип т. Какой способ передачи и получения объектов типа т в качестве аргу- 64 Часть Ь Методы ментов функций наиболее эффективен? В общем случае сложные типы эффективнее всего передавать по ссылке, а скалярные — по значению.
(К скалярным типам отно- сятся арифметические типы, описанные ранее, например епца, указатели и указатели на члены класса.) Для сложных типов это позволяет избежать ненужных затрат вре- мени на вызовы конструкторов и деструкторов, а для скалярных типов — избыточных способов доступа к переменным, предоставляемых ссылками. Не забудьте, что в языке С++ указатели на ссылки не допускаются.