Б. Страуструп - Дизайн и Эволюция C++. 2006 (1160775), страница 85
Текст из файла (страница 85)
Пяряов легко осущястэимо, ко второму яо многих случаях удается приблизиться». Итак, ключевые вопросы выстраивались следующим образом: удобство нотации, эффективность выполнения и безопасность с точки зрения типов. Основные ограничения — переносимость и приемлемая производительность компилятора Зачем нужны шаблоны ПИИИИИКИ и компоновщика, включая иистаицировапие шаблонов классов и функций, прямо или косвенно используемых в программе.
Основные идеи о предполагаемых функциях параметризоваииых типов рождались при иаписании программ, где шаблоны имитировались с помощью макросов. Кроме меня, этим занимались Эндрю Кениг, Джонатан Шопиро и Алекс Степанов. Мы написали много макросов в стиле шаблонов, чтобы понять, какие языковые средства необходимы для поддержки данного стиля программирования. Размышляя иад шаблонами, я ие отводил главное место языку Ас!а, который лишь вызывал у меня раздражение своими операторами иистаицироваиия шаблонов (см.
раздел 15.10.1). Однако Алекс Степанов хорошо знал данный язык, поэтому некоторые из характерных для Ас!а приемов, вероятно, перешли в С++. Ранняя версия шаблонов реализована в варианте С(гопС в 1989 г., автор — Сэм Харадхвала из компаиии ОЬ)есс Пез!яп 1пс. Поддерживались только шаблоны классов. Затем Стэн Липпмаи расширил версию до полной реализации и поддержал механизм иистаицироваиия шаблонов, спроектированный Глеиом МакКласки (О!ап МсС!из!сеу) при участии Тони Хансена, Эндрю Кеиига, Роба Мюррея и моем !МсС!цз!сеу, 19921.
Мэри Фонтана и Мартин Нит (Матс!и ИеаС!с) из Техаз 1пзспппепсз написали свободно распространяемый препроцессор, в котором был реализован один из вариантов шаблонов !Ропсапсс 1991]. Несмотря иа полученный опыт, мы все еше опасались включать в стандарт то, что ие вполне понято, поэтому в АВМ мехаиизм шаблонов сознательно был определен в сокращенном виде.
Уже тогда стало понятно, что это слишком усеченный вид, ио гораздо труднее исключить неудачные средства, чем добавить новые. Механизм шаблонов, изложенный в АВМ, комитет АМ51 С++ одобрил в июле 1990 г. Важным доводом в пользу включения шаблонов в предварительный стандарт стало сделанное членами комитета наблюдение, что уже имелось более полумиллиона строк реально использовавшегося кода иа С++, где применялись шаблоиы и их заменители. Появление шаблонов стали переломным моментом в процессе перехода от одной стратегии проектирования нового средства в С++ к другой. Ранее примеиялись реализации, использования, обсуждения и повторные реализации.
После включения в язык шаблонов все новые средства подробно обсуждались в комитете по стандартизации, а реализация шла параллельно этому обсуждению. Дискуссия по поводу шаблонов ие была достаточно всесторонней, и в результате многие аспекты шаблонов пришлось пересматривать, базируясь иа опыте последующей реализации и применения. Цель, ради которой создавались шаблоны, была достигнута. В частности, даиное средство позволяет проектировать эффективные, компактные и безопасные с точки зрения типов контейнерные классы и удобно ими пользоваться.
Без шаблоиов проектировщику пришлось бы прибегать к слабо или динамически типизироваииым вариантам, что отрицательно сказалось бы иа структуре и эффективности программы. Но я был слишком осторожен при специфицировании свойств шаблонов. Ведь такие возможности, как явная спецификация аргументов шаблона функции (см. раздел 15.6.2), выведение аргументов шаблона функции, ие являющихся шаблоны ПИИИИИВВ типами (см.
раздел 15.б.1), и вложенные шаблоны (см. раздел 15.9.3), можно было включить в язык сразу. Это бы несильно отразилось на сложности компилятора, а пользователям помогло. С другой стороны, я не предложил достаточной поддержки разработчикам компиляторов в плане инстанцирования шаблонов (см.
раздел 15.10). Предложение было передано на рассмотрение комитета А]ч[81/150 по стандартизации. Правила привязки имен, механизм явного инстанцирования, ограничения на специализацию и явная квалификация вызовов шаблонов функций одобрены для включения в С++ на заседании комитета в Сан-Хосе в ноябре 1993 г. как часть обшего плана совершенствования определения шаблонов.
15.3. Шсзбз)ОНЫ (ц]ЭССО~ Ключевые конструкции излагались следующим образом [5сгоизсгпр, 1988Ъ]: «В С++ параметризованный тип называется шаблоном класса. Он описывает, как момно конструировать отдельные классы, точно так ма, как сам класс описывает конструирование индивидуальных обьектов. Шаблон класса вектора можно было бы объявить так: севр1асе<с1аве т> с1аав чессог ( Т* ч; 1пс ат; ри)>11с: чесСог(гпС); ть орегасог[)(1пс); та е1ет(1пс 1) ( гесигп ч[1] 1 ): Префикс с емр1а се< с 1 аа е т> дает понять, что объявляется шаблон и что внутри обьявления будет использоваться аргумент т типа (уре [тип, переданный при объявлении). После этого в области действия объявления шаблона Т можно использовать точно так жв, как любое имя любого другого типо.
Объявленные векторы допускается применять следующим образом: чесгог<1пс> ч1(20)г чессог<соер1ех> ч2(30); сурес)еГ чесгог<совр1ех> очес/ // счес - синоним для чесгог<соир1ех> очес чЗ(40)г // ч2 и ч3 имеют один и тот яе тип чоЫ 1() ( ч1[3] = 7г ч2[3] = чЗ.е1ет(4) = сомр1ех(7,8)г ) Пользоваться шаблонами не сложнее, чем классами. Полные имена экземпляров шаблона класса, такие как чесСог<1пС> или чесСог<совр1ех>, легко читаются. Быть может, данная запись даме понятнев, чем нотация для массива встроенного типа: 1пс [ ] и сонр1ах [ ) .
Если полное имя оказывается слишком длинным, то момно ввести сокращение с помощью суре<)ег. Шаблоны классов ЯИИИИИФБИ Объявить шаблон класса лишь немного сложнее, чем сам класс. Ключввов слово с1авв используется для того, чтобы обозначить аргументы типо )урв. С одной стороны, оно вполне подходит для этого, с другой — отпадает необходимость вводить новое ключевое слово. В данном контексте с1а э а означает «любой тмп», а не только «тип, определенный пользователем». Угловые скобки <...
> используются вместо фигурных (... ) с целью подчеркнуть иную природу аргументов шаблона, о также потому, что (... ) используются в С++ слишком часто. Ключевое слово Селгр1ага введено, чтобы объявления шаблонов находилмсьслегкостью, а шаблоны классов и функций были обеспечены единым синтаксисом». Шаблоны — это механизм генерирования тинов. Сами по себе они не являются типами, никак нс представлены во время исполнения, поэтому не оказывают влияния на модель размещения объекта в памяти.
Я хотел, чтобы новое средство не уступало в эффективности макросам, ведь по идее шаблоны должны использоваться для представления таких низкоуровневых типов, как массивы н списки. Поэтому важной возможностью представлялось встраивание. В частности, я полагал, что наличие стандартных шаблонов для массива и вектора — единственный разумный способ поместить низкоуровневую концепцию массива С в глубь языка. Но более высокоуровневые альтернативы— массив с контролем выхода за границу и оператором эйке (), многомерный массив, векторный тип с надлежащей семантикой операций и копирования н т.д.— пользователи примут только в случае, если быстрота действия, расход памяти и удобство нотации будут пе хуже, чем для встроенных массивов.
Другими словами, механизм реализации параметризованных типов должен быть таким, чтобы программист мог заменить обычные массивы стандартным библиотечным классом (см. раздел 8.5). Естественно, встроенные массивы попрсжнему останутся в языке: они необходимы части пользователей и применяются в миллионах строк кода. Однако я хотел предложить эффективную альтернативу тем, кто ценит улобство и безопасность типов больше совместимости.
Кроме того, в С++ поддерживаются виртуальные функции, а следовательно, любая концепция, для которой в очевидной реализации потребовалась бы таблица переходов. Например, «истинно абстрактное» множество, состоящее из элементов типа т, можно было бы реализовать как шаблон абстрактного класса с виртуальными функциями, применяемыми к объектам т (см. раздел 13.2.2). Поэтому я начал искать решения, где основная нагрузка ложилась бы на компилятор, обеспечивая при этом близкую к оптилгальной производительность в процессе выполнения как по времени, так и по памяти. 15.3.1.
Аргументы шаблонов, не являющиеся типами Кроме аргументов-типов С++ допускает в шаблонах и аргументы, не являющиеся типами. Предполагалось, что они будут использоваться главным образом для задания размеров и верхних границ контейнерных классов. Например: Сепр1аге<с1аав Т, 1пт 1> с1ааа Ваггег ( Т т(1); (пс эз; риЫ(с: Ваг(ет() : аз(1) () уl ); Шаблоны ИИИИИИИ!1 Такие шаблоны важны, если речь идет о конкуренции с массивами и структурами С в плане зффективности и компактности представления. Передача размера позволяет разработчику контейнера избежать использования свободной памяти. Если бы аргументы, не являющиеся типами, не поддерживались, то пришлось бы передавать размер через тип массива, как в следующем примере: Гешр1асе<с1авв т, с1авв й> с1авв Виг й т; (пс вв; риЫ1с г Вцг () г вз(в1веог(й) /в1веог (Т) ) () // ): вп(<1пг, гпг(700]> Ь; Это решение неудачно, подвержено ошибкам и не подходит ни к каким типам, кроме целых.
А я еще хотел для большей гибкости дать возможность передавать в качестве аргумента шаблона указатель на функцию! В первоначальном проекте в качестве аргументов не могли выступать шаблоны н пространства имен. Теперь я не вижу причин запрещать такие аргументы, тем более что их полезность очевидна. Передача шаблонов классов в качестве аргументов шаблонов одобрена на заседании комитета в Сан-Лиего в марте 1994 г. 15.4. Ограничения на аргументы шаблонов Па аргументы шаблонов не накладывается ограничений.
Проверка типов откладывается до момента инстанцнрования шаблона (Б(гоцвггцр, 1988Ь1: «Стоит ли требовать от пользователя, чтобы он задавал набор операций, применимых к аргументу шаблона типа (трет Например: // для аргумента шаблона типа Т должны быть заданы // операции =, ==, < н <= Сешр1аге < с1авв Т ( та орегагог=(сопел та); (пг орегагог==(сопел ть, сопел та)г (пг орегагог<=(сопел та, сопел та)г тпг орегасог<[сопвг Та, сопел та); > с1авв теолог ( // Нет. Требование обязательно задавать такую информацию снижает гибкость средств параметризации, не упрощая реализацию и не повышая безопасность.