А. Александреску - Современное проектирование на C++ (1119444), страница 16
Текст из файла (страница 16)
Таким образом, ес- ли объект класса т уже является ссылкой, то новую ссылку на нее создавать не следует. Несложный анализ оптимальных типов параметров функции приводит к следую- шему алгоритму. Рассмотрим тип параметра с именем пагаеесегтуре. Если класс т — это ссылка на некоторый тип, классы Рагааетегтуре и т совпадают (ссылки на ссылки не допускаются). В противном случае, если класс т — это скалярный тип (5 от, 11оат и т.п.), то класс пагааетегтуре — это класс т (основные типы лучше всего передавать по значению), иначе класс Рагавееегтуре является типом сопзт тй (неэлементарные типы лучше передавать по ссылке).
Одно из достоинств этого алгоритма состоит в том, что он позволяет избежать ошибки, связанной с использованием ссылки на ссылку, которая может возникнугь при совместном использовании функций Ы пд2пд и пеа Гцп из стандартной библиотеки. Класс туретга)гз легко реализовать с помошью приема, который мы уже применяли, и определенных выше характеристик яеГегепседтуре и )звгзез тзуе. еепр1ате <турепаве т> с1азэ туретгазсз ( ...
как и раньше ... рцЬ1з с: суреде~ ве1есг<завтддгзтЬ !! )зро)птег )! зэмевЬегвозптег, т, яеФегепседтурее>: гаези1г рагааехегтуре' К сожалению, эта схема не позволяет передавать по значению параметры перечислимых типов, поскольку невозможно определить, является заданный тип перечислимым или нет.
Класс туретгазтз::пагааетегтуре используется в шаблонном классе ьцпстог, определенном в главе 5. 2. 10.4. Удаление каалификатороа Имея тип т, можно легко получить константу, очень похожую на обычную константу сопзт т. Однако выполнить обратную операцию (т.е. удалить квалификатор сопэс) намного труднее. Кроме того, иногда возникает необходимость избавиться и от квалификатора типа чо1атз1е. Рассмотрим, например, создание интеллектуального указателя Баагспсг (глава 7). Если бы мы захотели предоставить пользователю возможность создавать интеллектуальные указатели на константные объекты, например ваагтртг<сопзх иЫдег>, пришлось бы модифицировать указатель на объект класса из дйец В этом случае в классе В|кагтртг следовало бы создавать обьект класса пз гойет на основе константною объекта.
65 Глава 2. Приемы программирования Реализовать такой "ликвидатор" достаточно просто. Для этого нужно применить частичную шаблонную специализацию. севр1асе <сурепаве т> с1азв туретгатсв ... как и раньше ... рг1часе: севр1асе <с1азз и> зсгисс ипсопзс ( суредеУ и аези1с; ); севр1асе <с1азз и> зсгисс ипсопзС<сопзС и> ( суредеР и яези1с; рио1зс: суредеГ ипсопвс<т>яези1с нопсопзстуре; 2. 20.6. Применение класса ТуреТгаИа Класс ТуреТгаттз предоставляет много интересных возможностей.
Например, с помощью описанных выше приемов можно реализовать процедуру Сору, используюшую функцию в)св1азс (проблема, упомянутая в разделе 2.10). Для зтого можно применить класс тга1сзтуре, позволяюший получить информацию о двух итераторах, и шаблонный класс Хпс2туре, осушествляюший диспетчеризацию вызова либо функции в)св1азс, либо классической процедуры копирования. епив соруя1оове1ессог ( сопзегчасдче, Раас ); // классическая процедура применяется ко всем типам севр1асе <сурепаве Хпсс, сурепаве Оиссс> оисхс сорухвр1(хпхс Л гзс, хпсс 1азс, оисхс гези1с, Хпс2туре<Сопзегчас(че> Рог (; Л гзс != 1азс; ++Рз гзс, ++гези1с) *гезн1с = "Рзгзс; геснгп гези1с; // выстрая процедура применяется только // для указателей на простые данные севр1асе <сурепаве хпхс, сурепаве оиссс> оисхс сорухвр1(Хпсп й гЗС, Хпсс 1азс, оисхс гези1с, Хпс2туре<казс>) ( сопзс ззхе с и = 1азс-Нгвс; взсв1азс(Н гзс, гези1с, п " з1хеоР(>Н гзс)); гесигп геви1с + и; севр1асе <сурепаве хпхс, сурепаве оисхс> оисхс сору(хпсс Р1гзс, хпсс 1азс, оисХс гези1с) суредеР туретга1сз<хпХс>::Розптеетуре 5гсРо(псее; суредеР туретгатсз<оисхс>::Ротпсеетуре оезсро(псее; епив ( соруя1оо = ТуреТгайтз<Хп1С>::15Ро)птег ев туретгазсз<оисХс>::ззяозпсег вв туретгазсз<5гсрозптее>::Ззвтдкипдавепса1 бб Часть!.
Методы туретга!сз<оезспо!псее>::!55сдгцпдавепса1 М з!геоГ(5гспо!псее) == ззгеоГ(оезспо!псее) 2 газс сопзегчас!че )!" гесцгп сорухвр1(Г! гзс, 1азс, геьц1с, хпс2туре<сорул1до>) Несмотря на то что процедура Сору сама по себе не слишком сложна, в ней есть один интересный момент. Перечислимое значение сорул1до позволяет делать выбор среди разных реализаций. Логика этого выбора такова: функция аз св1азс использу- ется, если оба итератора являются указателями, и оба типа, на которые ссылаются указатели„являются основными и имеют одинаковый размер. Послелнее условие не- обычно. Рассмотрим такой фрагмент кода. !пс* рх = ...; зпс* р2 = ...; опзздпед Зпс* рЗ = ...; Сору(РХ, р2, рЗ); В этом варианте функция сору вызовет функцию быстрого копирования, как и положено, хотя типы источника и адресата отличаются друг от друга. Недостаток функции сору заключается в том, что она не ускоряет то, что можно было бы ускорить.
Например, для простой структуры, характерной для языка С, со- держашей лишь данные элементарных типов — так называемой структуры сгнарых лросгаых данных (о!д р)а)п дага мшсшге), или РОО-структуры, стандартом предусмот- рено побитовое копирование. Однако функция сору не распознает простые структуры и вызывает медленную процедуру копирования. Здесь, кроме класса туретгазсз, нужно снова применить классические характеристики. севр1асе <сурепаве т> зсгисс 5иррогСВ!Св(зеСору ( елков ( геао1с = туретга!сз<т>::!55сдгцпдавепса1 ]; севр1асе <сурепаве хпхс, сурепаве оосхс> оосхс сору(хпхс г! гзс, хпхс 1азс, оцсхс гезо1с, хпс2туре<сгие>) ( суредеб туретга!сз<хпхс>:гро!псеетуре 5гспо!псее; суредеФ туретга!са<оосхс>):яо!псеетуре оезспо!псее; епцв ( изев(св1азс = суретга!са<хпхс>::ззрохпсег в8 суретга!сз<оосхс>::!зро!псег аа 5цррогСВ!Св!зесору<5гспозптее>::гези1с йй 5цррогСВ!Св!ЗЕсору<оезСРО!птее>::геац1с ва з!геок(5гсяо!псее) == 5(геоб(оезспохпсее) ) гесцгп сорухвр1(Гз гас, 1азС, ХпС2туре<изев!св1азс>); ) теперь, чтобы применить функцию в(св1аь с для РОР-типов, достаточно специализировать шаблонный класс 5иррогсвз сад зеСору и задать в нем значение сгибе.
севр1асе<> ьсгисс 5иррогСВ!Св!зеСору<иуСору> ( епцв ( геац1с = сгце ); ); 2. гО.б. Заключение В табл. 2.1 показано все множество характеристик. Реализованных в библиотеке (.оИ. 67 Глава 2. Приемы программирования 2.11. Резюме ° Статические г)иагнаснгические ун~верждения (раздел 2.1) позволяют библиотекам генерировать осмысленные сообщения об ошибках. ° Частичная игабланнал глециилизиция (разлел 2.2) позволяет специализировать шаблоны не лля фиксированного специального набора параметров, а для семейства параметров, наиболее соответствующих заданному шаблону.
° Пакальные классы (раздел 2.3) попускают интересные возможности, особенно в отношении шаблонных функций. ° Отображение целочисленных кангтинт в н~илы (раздел 2.4) облегчает процесс статической диспетчеризации, основанной на числовых значениях (особенно булсвско~ о типа). ° Отибражение между лшлами (раздел 2.5) позволяет заменить перегрузку функций частичной специализацией шаблонов (свойство, которого в стандарте языка С++ нет). ° Выбор тинов (разлел 2.6) позволяет выбирать типы на основе анализа условных выражений. ° Риглазнавание конвертируемости и нигледавания на зтане компиляции (разлел 2.7) лает возможность получать информацию о том, можно ли преобразовать лва заланных типа лруг в друга, являются они псевлонимами одного и того же типа или наследуют свойства друг друпь ° Класс туретпГо (раздел 2.8) реализует оболочку для класса зтд::туре (пто, опрелеляя семантику значений и операции сравнения.
° Классы нц11туре и гзартутуре (раздел 2.9) играют роль структурного нуля в метапрограммировании шаблонов. ° Шаблон туретга(тз (разлел 2ПО) прелоставляет множество характеристик общего предназначения, которые можно использовать для настройки кода на специфическую категорию типов. Таблице 2.1. Члены класса ТуреТга(тв<Т> Описание Имя Вид 1зро(птег Булевская константа Принимает значение тгце, если класс т является параметром Является типом, на который ссылается тип Т, если класс Т является указателем, в противном случае является типом нц11туре Принимает значение тгце, сели класс Т является ссылочным типом Если класс Т является ссылочным типом, класс Лвтегепседтуре является типом, на который ссылается класс т. В противном случае класс йегегепседтуре сам является классом Т ро1птеетуре Тип 1зяеКегепсе Булсвская константа яеГегепседтуре 1 ил 68 Часть Б Методы Описанные приемы программирования образуют строительные конструкции для созлания компонентов, представленных в книге.
Большинство этих приемов основано на шаблонных колах. Окончание юабь 2.! Имя Описаиие твсопвт Булевская константа нопсопвттуре т'вчго1атт'1е Тип Булевская константа нопчо1агт'1етуре Тип т'55тдбт'дпедтпт Булевская константа т'а5сдтптедга1 т'55тдя1оат Булонская константа Булонская константа 555гддгбтП Булевская константна 69 рагаметегтуре Тип нопаца1тттедтуре Тип т'55гдцпвт'дпедхпс Булонская константа т55тдяцпдаеепта1 Булсвская константа Глава 2. Приемы программирования Оптимально соответствует параметру неизменяемой функции. Может быть либо типом т, либо типом сопят тй Принимает 'значение тгце, если класс Т является константным типом Удаляет квалификатор сопят у типа т, сели он у него есть Принимает значение сгце, если класс т является типом с квалификатором ио(атт'1е Удаляет квалификатор уо1асз 1е у типа т, если он у него есть Улаляет квалификаторы сонат и ио1агз 1е у типа Т, сали они у него есть Принимает значение тгце, если класс т является одним из следующих четырех беззнаковых типов (цпвтдпед сйаг, цпвздпед зйогт т'пт, ипат'дпед тпт ичи ипат'дпед 1опд зпт) Принимает значение тгце, если кчасс является одним из следующих четырех типов со знаком (зтдпед сПаг, аПогт тот, 51дпед тпт или 1опд тпт) Принимает значение тгце, если класс т является обычным целочисленным типом Принимает значенис тгце, если класс т является обычным типом чисел с плавающей точкой (Ф1оат, доцЫ е или 1опд доцЫ е) Принимает значение сгце, если класс т является стагшартным арифметическим типом (целочисленным или с плаваюшеи точкой) Принимает значение тгце, если класс т является основным типом (арифметическим или уо(д) Списки типов Списки типов представляют собой средство для манипулирования коллекциями типов.