Программирование >>  Инициализация объектов класса, структура 

1 ... 159 160 161 [ 162 ] 163 164 165 ... 395


template <typename Type>

Type min( Type t1, Type t2 )

return t1 < t2 ? t1 : t2;

видит шаблон:

он сохраняет внутреннее представление min() , но и только. Позже, когда встретится ее

int i, j; реальное использование, скажем:

double dobj = min( i, j );

компилятор строит определение min() по сохраненному внутреннему представлению.

Здесь возникает несколько вопросов. Чтобы компилятор мог конкретизировать шаблон функции, должно ли его определение быть видимо при вызове экземпляра этой функции? Например, нужно ли определению шаблона min() появиться до ее конкретизации c целыми параметрами при инициализации dobj? Следует ли помещать шаблоны в заголовочные файлы, как м1 поступаем с определениями встроенных (inline) функций? Или в заголовочные файлы можно помещать только объявления шаблонов, оставляя определения в файлах исходных текстов?

Чтобы ответить на эти вопросы, нам придется объяснить принятую в C++ модель компиляции шаблонов, сформулировать требования к организации определений и объявлений шаблонов в программах. В C++ поддерживаются две таких модели: модель с включением и модель с разделением. В данном разделе описываются обе модели и объясняется их использование.

10.5.1. Модель компиляции с включением

Согласно этой модели мы включаем определение шаблона в каждый файл, где этот шаблон конкретизируется. Обычно оно помещается в заголовочный файл, как и для

model1.h

модель с вкчением:

определения шаблонов помещаются в заголовочн файл

template <typename Type>

Type min( Type t1, Type t2 ) {

return t1 < t2 ? t1 : t2;

встроенных функций. Именно такой моделью мы пользуемся в нашей книге. Например:

10.5. Модели компиляции шаблонов А

Шаблон функции задает алгоритм для построения определений множества экземпляров функций. Сам шаблон не определяет никакой функции. Например, когда компилятор



определения шаблонов включены раньше используется конкретизация шаблона #include model1.h

int i, j;

min() :

double dobj = min( i, j );

Заголовочный файл можно включить в несколько файлов с исходными текстами программы. Означает ли это, что компилятор конкретизирует экземпляр функции min() с целыми параметрами в каждом файле, где имеется обращение к ней? Нет. Программа должна вести себя так, словно min() с целыми параметрами определена только один раз. Где и когда в действительности конкретизируется шаблон функции, оставляется на усмотрение разработчика компилятора. Нам достаточно знать, что где-то в программе нужная функция min() была конкретизирована. (Как мы покажем далее, с помощью явного объявления конкретизации можно указать, где и когда оно должно быть выполнено. Такие объявления желательно использовать на поздних стадиях разработки продукта для улучшения производительности.)

Решение включать определения шаблонов функций в заголовочные файлы не всегда удачно. Тело шаблона описывает детали реализации, которые пользователям не интересны или которые мы хотели бы от них скрыть. В действительности, если определение шаблона велико, то количество кода в заголовочном файле может превысить разумные пределы. Кроме того, многократная компиляция одного и того же определения при обработке разных файлов увеличивает общее время компиляции программы. Отделить объявления шаблонов функций от их определений позволяет модель компиляции с разделением. Посмотрим, как ее можно использовать.

10.5.2. Модель компиляции с разделением

Согласно этой модели объявления шаблонов функций помещаются в заголовочный файл, а определения - в файл с исходным текстом программы, т.е. объявления и определения шаблонов организованы так же, как в случае с невстроенными (non-inline) функциями.

model2.h

модель с разделением

сюда помещается только объявление шаблона template <typename Type> Type min( Type t1, Type t2 ); model2.C

определение шаблона export template <typename Type>

Например:

Type min( Type t1, Type t2 ) { /* ... */ }

Программа, которая конкретизирует шаблон функции min() , должна предварительно включить этот заголовочный файл:

Этот заголовочный файл включается в каждый файл, где конкретизируется функция



user.C

#include model2.h int i, j;

double d = min ( i, j ); правильно: здесь производится конкретизация

Хотя определение шаблона функции miin() не видно в файле user.c, конкретизацию min(int,int) произвести можно. Но для этого шаблон min() должен быть определен специальным образом. Вы уже заметили, как именно? Если вы внимательно посмотрите на файл model2.c, то увидите, что определению шаблона функции min() предшествует ключевое слово export. Таким образом, шаблон miin() становится экспортируемым. Слово export говорит компилятору, что данное определение шаблона может понадобиться для конкретизации функций в других файлах. В таком случае компилятор должен гарантировать, что это определение будет доступно во время конкретизации.

Для объявления экспортируемого шаблона перед ключевым словом template в его определении надо поместить слово export. Если шаблон экспортируется, то его разрешается конкретизировать в любом исходном файле программы - для этого нужно лишь объявить его перед использованием. Если слово export перед определением опущено, то компилятор может и не конкретизировать экземпляр функции min() с целыми параметрами и нам не удастся связать программу.

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

Ключевое слово export в объявлении шаблона, находящемся в заголовочном файле, можно опустить. Так, в объявлении miin() в файле model2 .h этого слова нет.

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

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

компилятор несколько раз конкретизирует шаблон функции с одним и тем же множеством аргументов, что приводит к ошибке повторного определения функции при связывании программы;

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

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

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



1 ... 159 160 161 [ 162 ] 163 164 165 ... 395

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