Б. Страуструп - Дизайн и Эволюция C++. 2006 (1160775), страница 90
Текст из файла (страница 90)
75.9.3. ШдбЛОНЫ-ЧЛЕНЫ Единственная причина, по которой, согласно АКМ, шаблоны ие могут являться членами классов, — я ие смог убедить себя, что такую возможность будет легко реализовать. Шаблоиы-члеиы входили в первоначальный проект шаблонов, и в целом я за то, чтобы любые конструкции, вводящие область действия, имели вложеиисяе формы (см. разделы 3.12 и 17.4.5.4). Но если бы я безо всяких ограничений разрешил в С++ шаблоны-члены, то нечаянно разрушил бы модель размещения объекта в памяти, что отбросило бы иас иемиого назад. Рассмотрим решение задачи двойной диспетчеризации (см. раздел 13.8.1): с1авв БЬаре ( // Сепр1аСе<с1авв Т> урхСоа1 Воо1 !поесвесС(сопяС Та) сопвС =0; с1авв ВесСапд1е : роЬ1!с БЬаре ( // севр1асе<с1аяв Т> ч1ссоа1 воо1 1псегвесс(сопяс та в) сопвс; Инстанцирование шаблонов 16ИИИИИКИ Сешр1асе<с1анв Т> твггца1 Воо1 Вестапд1е::1птегвесг(сопят Та в) сопят ( гесотп в.гпсетвесс(*с)т1в)г т/ *савв - это кессапд1е у/ разрешаем в зависимости от в ) Этот пример просто обязан быть незаконным, иначе пришлось бы вводить дополнительный элемент в таблицу виртуальных функций для класса В)таре всякий раз, как кто-то вызовет ВЪаре г: 1псегэесг ( ) с новым типом аргумента.
Это означало бы, что создавать таблицы виртуальных функций и размещать в них указатели на функции может только компоновщик. Поэтому шаблон-член не может быть виртуальным. Я обнаружил это уже после выхода АКМ, так что ограничение, согласно которому шаблоны можно определять только в глобальной области действия, оказалось просто спасением. С другой стороны, упомянутые в этом разделе проблемы преобразования из-за отсутствия шаблонов-членов не имею г решения. Шаблоны- члены одобрены комитетом на заседании в Сан-Диего в марте 1994 г.
Во многих случаях альтернативой вложенным шаблонам классов служит явное задание аргументов шаблонов функций (см. раздел 15.6.2). 15.10. Инстанцирование шаблонов Первоначально (15ггопзггпр, 1988Ъ), [АВМ)) в С++ не было оператора для «инстанцирования» шаблона, то есть операции явного генерирования объявления класса и определений функций для конкретного набора аргументов шаблона. Лишь имея полную программу, можно узнать, какие шаблоны следует инстанцировать. Часто они определяются в библиотеках, а инстанцирование производится в результате действий пользователей, даже не подозревающих о наличии таких средств. Поэтому запрос инстанцирования, например, с помощью оператора пеы из А((а или подобного ему пользователю представлялся неразумным.
Более того, если бы существовал оператор инстанцирования шаблона, он должен был бы грамотно обрабатывать случай, когда две не связанных между собой части программы требуют инстанцировать одну и ту же функцию с одним и тем же набором аргументов. В этом случае приходилось бы избегать дублирования кода и не потерять возможность динамического связывания. В АКМ приводятся комментарии на данную тему, но окончательного ответа не дается: «Решение о том, какие функции генерировать из определения шаблона функции, нельзя принять, пока нет полной программы, то есть до тех пор, пока не станет ясно, какие функции нужны.
Принято, что обнаружение ошибок откладывается до последнего момента: когда после начальной стадии компоновки уже сгенерированы определения из шаблонов функций. Но многим может показаться, что зто слишком поздно. Кроме того, правило возлагает максимальную ответственность на среду программирования. Именно системе поручается найти определения шаблонов классов, шаблонов функций и классов, необходимых для генерирования определений функций по шаблонам. Для некоторых сред зто слишком сложно.
Шаблоны КИИИИИИ!1 Обв проблемы можно было бы смягчить, если ввести механизм, указывающий программисту, где сгенерировать определенные функции по шаблону с определенными аргументами. Это достаточно просто сделать в любой среде программирования. Тогда ошибки, относящиеся к конкретному определению шаблона функции, будут обнаруживаться в точке запроса.
Неясно, однако, следует ли считать токой механизм частью языка или среды. Было решено, что необходимо накопить опыт, а пока — хотя бы на время — такие механизмы воспринимаются как часть среды. Простейший способ гарантировать правильную генерацию определений шаблонов функций — оставить решение на усмотрение программиста, Тогда компоновщик сообщит нужные определения, а файл, содержащий невстраиваемые определения шаблонов функций, можно будет откомпилировать, указав, какие будут использоваться аргументы шаблона. На базе такого подхода можно строить и более сложные системыз. Теперь имеется множество разных реализаций, Практика показала, что сложность проблемы не была переоценепа и что нынешние реализации не вполне удовлетворительны.
В компиляторе Сггопг [МсС!цзкеу, 1992] инстанцированне шаблонов автоматизировано, как и предполагалось в первоначальном проекте ]Ягоцзггцр, 1988Ъ] и в АКМ. Принцип таков: запускается компоновщик, и если оказывается, что какой-то шаблон функции не инстанцирован, то снова вызывается компилятор, который генерирует отсутствующий объектный код. Этот пропесс повторяется, пока не будут инстанцированы все шаблоны.
Определения шаблонов и типов аргументов (когда необходимо) базируются на соглашении.об именовании файлов. При необходимости влгесте с таким соглашением можно использовать отдельный задаваемый пользователем файл, в котором имена шаблонов и классов ставятся в соответствие файлам, где находятся их определения. У компилятора есть специальный режим для обработки инстанцирований шаблонов. Часто зта стратегия себя оправдывает, но в некоторых ситуациях возникают следуюпгие проблемы: сз низкая производительность компиляции и компоновки.
Если компоновщик определяет, что нужно инстанцирование, то приходится вызывать компилятор для генерирования необходимых функций. Затем компоновщик нужно вызвать снова. В системе, где компилятор и компоновщик не работают постоянно ', это может оказаться очень накладно. Хорогпий механизм библиотек может существенно уменьшить число запусков компилятора; сз плохая интеграция с системами контроля версий, имеющими четко определенные представления о том, что такое исходный код, ка"к из него получается объектный. Подобные системы плохо взаимодействуют с системами разработки, в которых для получения полной программы совместно используются компилятор, компоновщик и библиотека (способ описан в первом пункте); ся слабое сокрытие деталей реализации.
Если в реализации библиотеки используются шаблоны, то для того, чтобы пользователь лгог скомпоновать свою программу с моей библиотекой, я должен предоставить исходные То есть не находятся в дисковом каше операционной системы. — Прим. перев. Инстанцирование шаблонов йНИИИИИБ тексты шаблонов. Причина в том, что необходимость в иистаицироваиии шаблонов выявляется только иа последнем этапе компоновки. Описанную проблему можно обойти, если заранее каким-то образом удастся сгенерировать объектный код, содержащий все версии шаблонов, которые могут быть иистапцироваиы для моей библиотеки. В свою очередь, это может привести к неоправданному увеличению объектного кода, если разработчик попытается предусмотреть все возможные способы использования, — а ведь в каждом конкретном приложении будет задействована лишь малая их часть.
Отметим также, что, если ипстаицироваиие прямо зависит от того, какие шаблоны пользователь инстаицирует, оно по необходимости должно быть поздним. (з пользователю удастся задавать окружение для иистаицирования; (з ои также сможет заранее создавать библиотеки наиболее часто иистаицируемых шаблонов способом, мало зависящим от компилятора; о предварительно созданные библиотеки будут зависеть ие от изменений в среде программы, которая их используст, а только от контекста иистаицироваиия. Описанный здесь механизм иистацпирования по запросу одобрен иа заседании комитета в Са(ьХосе; ои основан па предложении Эрвина Упру (Егвчп Ппгц[(). Выбранный синтаксис соответствует тому, который используется при явном задании аргументов шаблона класса (см.