|
Программирование >> Полиморфизм без виртуальных функций в с++
и компоновки, о которых просят разработчики компиляторов. Заметим, что это модель системы инстанцирования, а не правило языка и не характеристика конкретной реализации. Возможно несколько альтернативных реализаций, но я полагаю, что пользователь может игнорировать детали (почти всегда) и представлять себе систему так, как описано выше. Рассмотрим предполагаемую работу компилятора в различных ситуациях. Как обычно, на вход компилятора подаются . с-файлы. Они содержат директивы #include для включения .h-файлов. Компилятору известно только о переданном ему коде. То есть в файловой системе никогда не ишется определение шаблона, которое не дано. Однако компилятор использует репозитарий, как бы запоминая, какие шаблоны уже известны и откуда они взялись. Эту схему легко расширить с учетом архивов. Вот краткое описание того, как происходит работа компилятора в некоторых ключевых точках: □ распознано объявление шаблона. Теперь шаблон .можно использовать. Он помещается в репозитарий; □ в . с-файле распознано определение шаблона функции. Шаблон обрабатывается с целью помещения в репозитарий. Еслрг он уже находится там, появляется ошибка повторного определения за исключением случаев, когда это новая версия того же шаблона; □ в . h-файле распознано определение шаблона функции. Шаблон обрабатывается с целью помещения в репозитарий. Если он уже там находится, то осуществляется проверка, был ли на самом деле ранее по.\1еще1П1ый шаблон добавлен именно из этого заголовочного файла. Если это пе так, диагностируем ошибку повторного определения. Проверяем, не нарушено ли правило одного определения. Для этого надо убедиться, что старое определение совпадает с новым. В противном случае диагностируем ошибку повторного определения, если только это не новая версия того же шаблона; □ распознано объявление специализации шаблона функции. Если необходимо, выдаем ошибку об использовании до объявления. Теперь специализацию можно использовать. Помещаем объявление в репозитарий; □ распознано определение специализации шаблона функции. При необходимости выдаем ошибку об использовании до объявления. Теперь специализацию можно использовать. Помещаем определение в репозитарий; □ распознано использование. Заносим в репозитарий запись об использовании шаблона с данным набором аргументов. Смотрим, есть ли в репозитарий определение общего шаблона или его специализации. Если да, то допустимо выполнить контроль ошибок или оптимизацию. Если шаблон еще не использовался с таким набором аргументов, то допустимо сгенерировать код сейчас или отложить это до этапа компоновки; □ распознан запрос явного инстанцирования. Проверяем, определен ли шаблон. Если нет, выдаем сообщение о неопределенном шаблоне. Проверяем, определена ли специализация. Если да, выдаем сообщение инстанцирован и специализирован . Проверяем, был ли уже инстанцирован шаблон с данным набором аргументов. Если да, можно либо выдать сообщение о повторном инстанцирований, либо игнорировать запрос. В противном случае допустимо сгенерировать код сейчас или отложить это до этапа компоновки. В любом случае код генерируется для каждой функции-члена шаблона класса, которую видит компилятор; □ программа компонуется. Сгенерировать код для каждого использованного шаблона, код которого не сгенерирован ранее. Повторить этот процесс, пока не будут обработаны все инстанцировапия. Выдать сообшение использована, но не определена для всех отсутствующих шаблонов функций. При генерации кода пшблона для дашюго набора аргументов используется алгоритм поиска, рассмотренный в разделе 15.10.2. Разу.меется, должны вьшолняться проверки некорректного использования, недопустимой перегрузки и т.д. В компилятор могут быть заложены более или менее жесткие требования к исполнениям правила одного определения и правила, запрещающего многократное инстанцирование. Такая диагностика не является обязательной, поэтому поведение в .этих случаях следует считать лишь вопросо.м качества реализации. 15.11. Последствия введения шаблонов Отсутствие шаблонов в ранне.м С++ имело негативные последствия для использования языка. Теперь, когда шаблоны получили широкое распространение, какие задачи можно решать лучше? Из-за отсутствия шаблонов в С++ не было способа реализовать контейнерные классы, не прибегая к интенсивному использованию приведения типов и манипуляции объектами через указатели на общие базовые классы или void*. Теперь от всего этого можно отказаться. Но неправильное использование наследования, берущее начало в бездумно.м переносе в С++ .методов из Smalltalk (см., например, пункт 14.2.3) и злоупотребление слабой типизацией, заи.мствованной из С, выкорчевать будет очень трудно. С другой стороны, я ожидаю, что потихоньку удастся избавиться от небезопасной практики работы с массивами. В стандартной библиотеке ANSI/ISO есть шаблон класса динамического массива dynarray (см. раздел 8.5.), так что можно будет пользоваться либо и.м, либо каким-то самодельным шаблоном и не прибегать к массивам без контроля выхода за границы. Часто раздаются критические замечания, что в С и С++ не контролируются индексы массива. В большинстве случаев это недовольство беспочвешю, поскольку люди забьшают, что, хотя возможность ошибиться, выйдя за пределы массива, и есть, делать такую ошибку вовсе не обязательно. Шаблоны массивов переносят детали работы с низкоуровневыми массивами в глубь реализации, где им и надлежит находиться. По мере того как массивы в стиле С станут применяться все реже из-за того, что работа с ними будет перенесена в классы и шаблоны, число связанных с массивами ошибок резко уменьшится. Это и так постепенно происходит, а наличие шаблонов, особенно входящих в состав библиотек, ускорит процесс. Третий важный аспект работы с шаблона.ми состоит в том, что в сочетании с наследованием они открывают совершенно новые возможности для проектирования библиотек (см. раздел 15.8). Хотя компиляторов, поддерживающих шаблоны, и немало, но все же они пока не стали доступными повсеместно. Да и те, что есть, еще недостаточно совершенны. 15.11.1. Отделение реализации от интерфейса Механизм шаблонов задействован исключительно на этапах компиляции и компоновки. Он не нуждается ни в какой поддержке во время исполнения. Конечно, это сознательное решение, но остается одна проблема: как классы и функции, сгенерированные (инстанцированные) из шаблонов, .могут зависеть от информации, известной только на этапе выполнения. Обычный для С++ ответ-пользуйтесь виртуальными функция.ми. Многие выражали озабоченность тем, что шаблоны слишком сильно зависят от наличия исходного кода. В это.м видели два нежелательных побочных эффекта: □ нельзя засекретить коммерческую программу; □ если реализация шаблона изменяется, пользователь должен перекомпилировать свою профамму. Разумеется, так обстоит дело лишь в самых примитивных реализациях, но и в этом случае шаблон класса, который является производным от классов, предоставляющих ясный интерфейс, позволяет уменьшить неприятные последствия. Часто шаблон содержит просто интерфейсный код к чему-то секретному , что можно изменять, не затрагивая интерфейс. При.меры такой техники - шаблон pvector из раздела 15.5, шаблонная версия класса set из раздела 13.2.2. Для решения проблем можно воспользоваться концепцией виртуальных функций, так что мне не нужно предоставлять еще один вариант таблицы переходов. Можно также придумать форму хранения шаблонов в частично откомпилированном виде, тогда секреты производителя останутся в такой же мере безопасными, что и обычный объектный код. Для некоторых проблема состоит в том, как гарантировать, что пользователю не удастся - прямо или косвенно - инстанцировать новые версии шаблонов, которые по идее должны быть секретными. Но для этого достаточно просто не предоставлять исходный код. Данный подход реализуем, если производитель может заранее инстанцировать (см. раздел 15.10.1) все необходимые версии. Тогда эти (и только эти) версии можно поставлять в виде библиотек объектного кода. 75.77.2, Гибкость и эффективность Поскольку шаблоны призваны напрямую конкурировать с макросами, требования к их гибкости и эффективности очень высоки. Теперь уже можно сказать, что получившийся механизм обладает нужными свойствами в высшей степени и не жертвует при этом статически.м контролем типов. Когда дело доходит до выражения алгоритмов, мне иногда хочется иметь средства более высокого порядка, но никогда - контроль типов во время исполнения. Думается, что предлагаемые улучшения шаблонов за счет введения ограничений отрицательно сказались бы на их полезности, не увеличив безопасности, простоты или эффективности. Процитирую Алекса Степанова, который подвел итог опыту написания большой библиотеки структур данных и алгоритмов:
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |