Программирование >>  Полиморфизм без виртуальных функций в с++ 

1 ... 107 108 109 [ 110 ] 111 112 113 ... 144


Глава 15. Шаблоны

Ничто не дается с таким трудом, не оставляет столько сомнений в успехе и не сопряжено с большим риском, чем установление нового порядка вещей.

Никколо Макиавелли

15.1. Введение

Шаблоны и исключения были специально упомянуты в статье Whatis? [Stroustrup, 1986b] как желательные в С++ (см. раздел 3.15). Проектирование этих средств описано в работах [Stroustrup, 1988b], [Koenig, 1989b], [Koenig, 1990] и в ARM, a их включение в язык отражено в предложениях по стандартизации С++.

Первопричина появления шаблонов - желание параметризовать контейнерные классы. Механизм же исключений есть в языке, потому что изначально хотелось располагать стандартным способом обработки ошибок во время выполнения. В обоих случаях С предоставлял лишь очень примитивные средства, которые не позволяли программисту явно выразить свои намерения и не слишком хорошо совмещались с ключевыми концепциями С++. Еще со времен С with Classes .мы пользовались макросами для параметризации контейнеров (см. раздел 2.9.2), но макросы в С не могут работать с областями действия и типами и плохо увязываются с инструментальными средствами. Механизмы, которые в ранних версиях С++ использовались для обработки ошибок - имеются в виду set jmp/longjmp и индикаторы типа errno, - плохо сочетались с конструкторами и деструкторами.

Отсутствие таких механизмов приводило к неудачному проектированию, кодированию на излишне низком уровне и трудностям при совместном использовании библиотек, полученных из различных источников, то есть затрудняло работу на нужном (высоком) уровне абстракции.

На мой взгляд, шаблоны и исключения - это две стороны одной медали. Первые позволяют уменьшить число ошибок во время выполнения, расширяя спектр задач, с которыми может справиться статическая система типов. В свою очередь, исключения дают механизм для обработки оставшихся ошибок. С помощью шаблонов до разумного уровня можно довести число ошибок времени выполнения, которые обрабатываются с помощью исключений. Исключения предоставляют библиотекам, основанным на шаблонах, возможность уведомить вызывающую программу об ошибках.



15.2. Зачем нужны шаблоны

в первоначальном проекте С++ параметризованные типы рассматривались, но их пришлось отложить из-за нехватки времени на тщательное изучение вопросов проектирования и реализации, а также из-за боязни слишком усложнить компилятор. В частности, меня беспокоило, что неудачное проектирование может стать причиной замедления компиляции и компоновки. Я также считал, что удачная поддержка параметризованных типов значительно увеличит время, необходимое для переноса на другие платформы. К несчастью, мои опасения полностью подтвердились.

Шаблоны считались чрезвычайно важными средствами для правильного проектирования контейнерных классов. Впервые проект шаблонов был представлен на конференции USENIX по С++, состоявшейся в 1988 г. в Денвере [Stroustrup, 1988Ь]. В конце своего выступления я сказал:

В контексте С++ вопросы ставятся следующим оброзом:

а можно ли сделать параметризацию типа простой для применения?

□ удастся ли объекты параметризованного типа использовать так же эффективно, как и объекты жестко заданного типа?

а можно ли интегрировать в С++ параметризованные типы общего вида?

а возможно ли реализовать параметризованные типы так, чтобы скорость компиляции и компоновки была сравнима стой, которую обеспечивает система разработки, не поддерживающая пораметризацию типов?

□ удастся ли сделать такую систему компиляции простой и переносимой?

Таковы были мои критерии проектирования шаблонов. Конечно, са.м я был уверен, что на все эти вопросы удастся ответить положительно, Я утверждал, что фундаментальные альтернативы выглядят так:

При написании стандартной библиотеки сталкиваешься с серьезной проблемой - в С++ не предоставлено общих средств определения контейнерных классов : списков, векторов, ассоциативных массивов и т.д. Есть два подхода к реализации таких классов:

а в Smalltalk - опора на динамическую систему типов и наследование;

□ в Clu - на статическую систему типов и средства для работы с аргументами обобщенного типа type.

Первый подход очень гибок, но связан с высокими затратами и, что важнее, не позволяет статической системе типов обнаружить ошибки интерфейса. Второй традиционно ведет к довольно сложной реализации; средства компиляции и компоновки при этом тоже излишне сложны. Этому подходу также свойственна недостаточная гибкость, поскольку языки, в которых он использовался, прежде всего Ada, не имеют механизма наследования.

Изначально нам хотелось иметь в С++ механизм, так же хорошо структурированный, как в Clu, и имеющий столь же хорошие характеристики по времени исполнения и расходу памяти, но значительно быстрее компилируемый. Еще он должен быть таким же гибким, как в Smalltalk. Первое легко осуществимо, ко второму во многих случаях удается приблизиться .

Итак, ключевые вопросы выстраивались следующим образо.м: удобство нотации, эффективность выполнения и безопасность с точки зрения типов. Основные ограничения - переносимость и приемлемая производительность компилятора



и компоновщика, включая инстанцирование шаблонов классов и функций, прямо или косвенно используемых в программе.

Основные идеи о предполагаемых функциях параметризованных типов рождались при написании програм.м, где шаблоны имитировались с помощью макросов. Кроме меня, этим занимались Эндрю Кениг, Джонатан Шопиро и Алекс Степанов. Мы написали много макросов в стиле шаблонов, чтобы понять, какие языковые средства необходимы для поддержки данного стиля программирования. Размышляя над шаблонами, я не отводил главное .место языку Ada, который лишь вызывал у меня раздражение своими операторами инстанцирования шаблонов (см. раздел 15.10.1). Однако Алекс Степанов хорошо знал данный язык, поэтому некоторые из характерных для Ada приемов, вероятно, перешли в С++.

Ранняя версия шаблонов реализована в варианте Cfront в 1989 г., автор - Сэм Харадхвала из ко.мпании Object Design Inc. Поддерживались только шаблоны классов. Затем Стэн Липп.ман расширил версию до полной реализации и поддержал механизм инстанцирования шаблонов, спроектированный Гленом МакКлас-ки (Glan McCluskey) при участии Тони Хансена, Эндрю Кенига, Роба Мюррея и моем [McCluskey, 1992]. Мэри Фонтана и Мартин Нит (Martin Neath) из Texas Instruments написали свободно распространяемый препроцессор, в котором был реализован один из вариантов шаблонов [Fontana, 1991].

Несмотря на полученный опыт, мы все еще опасались включать в стандарт то, что не вполне понято, поэтому в ARM механизм шаблонов сознательно был определен в сокращенном виде. Уже тогда стало понятно, что это слишком усеченный вид, но гораздо труднее исключить неудачные средства, чем добавить новые.

Механизм шаблонов, изложенный в ARM, комитет ANSI С++ одобрил в июле 1990 г. Важным доводом в пользу включения шаблонов в предварительный стандарт стало сделанное членами комитета наблюдение, что уже имелось более полумиллиона строк реально использовавшегося кода на С++, где применялись шаблоны и их заменители.

Появление шаблонов стали переломным моментом в процессе перехода от одной стратегии проектирования нового средства в С++ к другой. Ранее применялись реализации, использования, обсуждения и повторные реализации. После включения в язык шаблонов все новые средства подробно обсуждались в комитете по стандартизации, а реализация шла параллельно этому обсуждению. Дискуссия по поводу шаблонов не была достаточно всесторонней, и в результате многие аспекты шаблонов пришлось пересматривать, базируясь на опыте последующей реализации и применения.

Цель, ради которой создавались шаблоны, была достигнута. В частности, данное средство позволяет проектировать эффективные, компактные и безопасные с точки зрения типов контейнерные классы и удобно ими пользоваться. Без шаблонов проектировщику пришлось бы прибегать к слабо или динамически типизированным вариантам, что отрицательно сказалось бы на структуре и эффективности программы.

Но я был слишком осторожен при специфицировании свойств шаблонов. Ведь такие возможности, как явная спецификация аргументов шаблона функции (см. раздел 15.6.2), выведение аргументов шаблона функции, не являющихся



1 ... 107 108 109 [ 110 ] 111 112 113 ... 144

© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки.
Яндекс.Метрика