А. Александреску - Современное проектирование на C++ (1119444), страница 17
Текст из файла (страница 17)
При этом к типам можно применять все основные операции, предусмотренные ддя обычных списков. В некоторых шаблонах проектирования описываются коллекции типов, над которыми производятся манипуляции. Эти типы либо связаны межау собой отношением наследования, либо не зависят друг от друга. Яркими примерами таких шаблонов проектирования являются шаблоны дбзтгаст кастогу и Ф зттог (папина е! а!., 1995).
Используя традиционные методы программирования, можно манипулировать коллекциями типов с помощью явного повторения. Зто приволит к раздуванию кода. Многие люди считают, что ничего лучше придумать нельзя. Однако списки типов позволяют автоматизировать задачи, которые программисты обычно решают с помощью макросов редактора. Списки типов придают языку С++ необычайную мощь, позволяя создавать новые, интересные идиомы. В этой главе содержится полное описание возможностей списков типов в языке С++, а также приводятся многочисленные примеры их применения.
Здесь представлена следующая информация. ° Концепция списков типов. ° Способы создания и функционирования списков типов. ° Методы эффективного манипулирования списками типов. ° Применение списков типов и программирование идиом, поддерживаемых списками типов. В главах 9 — 11 показано, как списки типов используются в качестве технологии программирования. 3.1. Зачем нужны списки типов Иногда нужно написать одни н тот же код для большого количества разных типов, и шаблоны тут ничем не могут помочь.
Рассмотрим, например, реализацию шаблона дьвтгаст кастогу (оагпта е! а!., 1995). ниже приведено определение виртуальной функции для каждого типа из некоторого набора, заданного на этапе проектирования. с!азз и!Йдеггасгогу риЬ!тс: чбгтца! нзпдон* Сгеатен!пдов() = О; чзгтоа) виттопэ СгеатевиттопО = О; чз'гтца) всго1)ваг* сгеатезсго1!вагО = О; ); Если концепцию абстрактной фабрики необходимо обобщить и реализовать в виде библиотеки, нужно предоставить пользователю возможность создавать фабрики произвольных наборов типов, а не только типов н(одоп, вцттоп и дсго11ваг. Шаблоны этой способностью не обладают.
Хотя на первый взгляд шаблон АЬзтгаст растогу не предоставляет широких возможностей для абстрагирования и обобщения, некоторые моменты достойны более глубокого изучения. 1. Если вы не можете обобщить основную концепцию, то вряд ли вам удастся обобшить ее конкретный пример. Это очень важный принцип. Если некая сущность не допускает обобщения, то программист вынужден постоянно иметь дело с конкретными воплощениями этой с)чцности, Напрнлзер, несмотря на то, что базовый класс абстрактной фабрики довольно прост, при реализации различных конкретных фабрик приходится прибегать к многократному повторению олного и того же кода.
2. Функциями- пенами класса н1одетгастогу невозможно свободно манипулировать (см. приведенный выше код). Набор сигнатур виртуальных функций в принципе невозможно сделать обобщенным. В качестве примера рассмотрим слелуюший код. темр1ате <с1авв т> т" магепебн(г)дет(н1с)детгастогуй Еастогу) т* рн = 1астогу.сгеатетО; // невозможно!1! рн->эетсо1ог(ясо); гетигп рн; Нужно вызвать функции Сгеатен1пс)оп, Сгеатевцттоп или Сгеате>сго11ваг, в зависимости от того, что представляет собой класс т — класс н1пг)оп, вцттоп или Бсго11ваг соответственно.
В языке С++ невозможно добиться такой подстановки текста. 3. И последнее (по порядку, но не по важности) — библиотеки только выиграли от того. что прекратились бесконечные дискуссии о соглашениях, принимаемых для записи имен (сгеасен1пдоп, сгеате п1пдоп или сгеатен1пбоп), и тому подобных мелочах. В библиотеках реализован легкий и стандартный способ принятия подобных решений. Абстрактные фабрики также должны были бы иметь такую возможность. Итак, подытожим наши пожелания.
Что касается п. 1, было бы прекрасно, если бы мы смогли создавать обьекты класса н1г)детрастогу, перелавая список параметров шаблонному классу АЬтзгастяастогу. турег)е1 АЬзтгастрастогу<н1пдоа, вцттоп, всго11ваг> н10детгастогу; Из п. 2 следует, что нам необходим шаблонный вызов для разных функций вида сгеатеххх. например, сгеате<н1пг)оп>о, сгеате<вцттоп>о и тд. тогда мы смогли бы вызывать эти функции с помощью обобщенного кода. темр1ате <с1аьэ т> т= ма)сеяедн1бдет(н1ддетгастогуй Уастогу) ( т* рн = гастогу.сгеасе<т>О; О вот это прекрасно! рн->ветсо1ог(ксо); гетцгп ркд 72 Часть!. Методы Однако мы не можем реализовать эти пожелания. Во-первых, оператор туребеФ для класса Мбцетгастогу применить невозможно, поскольку шаблоны не могут иметь переменное количество параметров.
Во-вторых, шаблонный синтаксис Сгеатеххк() недопустим, так как виртуальные функции не могут быть шаблонными. Итак, очевидно, что правила языка программирования не позволяют достичь высокого уровня абстракции и возможностей повторного использования кода. Списки типов позволяют снять эти ограничения и создать не только обобщенные абстрактные фабрики, но и реализовать много других шаблонов проектирования. 3.2. Определение списков типов По разным причинам язык С++ иногда позволяет программисту сказать: "Это лучшие пять строк кода, которые я когда-либо написал!".
Возможно, это связано с семантическим богатством этого языка или с необычностью его свойств. По этой традиции списки типов выглядят крайне просто. тевр1аге <с1ава т, с1аьа ц> атгцст туре1зат ( туребег т пеаб; туребег ц таз1; ); памеэрасе ть ( алгоритмы работы со списками типов Все, что относится к спискам типов, за исключением определения самого класса туре1(аг, пребывает в пространстве имен ты В свою очередь, пространство имен ТЕ находится внутри пространства имен библиотеки ( оЫ, как н весь код этой библиотеки. Для того чтобы упростить примеры. в этой главе упоминания пространства имен ть пропущены. Читателю следует помнить это, используя заголовочный файл туре- 1(эт.и. (Если вы забудете, компилятор вам напомнит!) Класс туре1зэт содержит два типа.
Доступ к ним обеспечивается внутренними именами неаб и таз1. Вот именно! Нам не нужны списки типов, содержащие три и больше элементов, поскольку они у нас уже есть. Например, рассмотрим список типов, состоящий из трех вариантов типа сваг. туребеУ туре1зат<спаг, туре1(эт<эзцпеб сваг, цпэ(цпеб сваг» сваг~ (эт; (Обратите внимание на раздражающий, но необходимый пробел между двумя грамматическими лексемами (гойеп) > в конце строки.) Списки типов не содержат никаких значений. Их тела пусты, они не имеют никакого состояния и не определяют никаких функционачьных возможностей.
Во время выполнения программы списки типов не содержат вообще никаких значений. Их единственное предназначение — предоставлять информацию о типах. Следовательно, любая обработка списков типов возможна лишь на этапе компиляции, а не в ходе выполнения программы.
Списки типов не предназначены для создания объектов, хотя в их создании нет ничего опасного. Таким образом, термин "список типов" означает тип списка, а не его значение, Значения списков типов не представляют никакого интереса. На практике применяются только их типы. (В разделе 3.13.2 показано, как списки типов можно использовать для создания коллекций значений.) Глава 3. Списки типов Здесь используется одна особенность, состояшая в том, что шаблонный параметр может иметь любой тип и быть конкретизацией своего собственного шаблона.
Это старое, хорошо известное свойство шаблонов, которое часто применяется при созда- нии таких необычных матриц, как чессог < чессог<дои)з)е». Поскольку класс туре1)зс имеет лва параметра, его всегда можно расширить, заменив один из пара- метров другим классом туре15 зс, и так до бесконечности. Оливка существует одна небольшая проблема. Пока мы можем создавать списки„ состояшие из нескольких типов, но у нас нет инструмента для описания списков, не содержаших никаких типов или содержаших только один тип, Для этого необходим нулевой лшл списка (пцй йаз суре) и класс нц11туре, описанный в главе 2, предназна- чен именно для этого. Примем соглашение, что каждый список типов должен заканчиваться классом нц11туре, служащим маркером конца списка, Это намного удобнее традиционного нулевого байта "х0", который применяется для обозначения конца строк в традици- онных функциях языка С. Теперь можно дать определение класса туре15 зс, состоя- шего лишь из одного элемента.