|
Программирование >> Разработка устойчивых систем
Как объяснялось ранее, эта директива может включаться в программу только один раз. #endif /:- OURMIN.Y III:- II: C05:OurMin.cpp linclude OurMin.h Определение minO tempiate<typenanie T> const T& min(const T& a, const T& b) { return (a < b) ? a : b: : C05:UseMinl.cpp {0} linclude <iostream> linclude OurMin.h void usemlnlO { std::cout mind.2) std::endl: } III:- II: C05:UseMin2.cpp {0} linclude <iostream> linclude OurMin.h void usemin2() { std::cout min(3.1.4.2) std::endl: } III:- II: C05:MinMain.cpp {L} UseMinl UseMin2 Minlnstances void useminlO: void usemin2(): int mainO { useminlO; usemin2(): } 111:- Если попытаться скомпоновать эту npoqjaMMy, компоновщик сообщит о неразрешенных внешних ссылках для min<int>() и min<double>(). Дело в том, что когда компилятор встречает вызовы специализаций min() в UseMinl и UseMin2, он видит только объявление min(). А раз определение недоступно, компилятор считает, что оно находится в другой единице трансляции, и не генерирует специализации в этой точке. Естественно, компоновщик жалуется на то, что специализации не найдены. Для решения проблемы мы создадим новый файл Minlnstances.cpp, в котором явно объявляются необходимые специализации min(): : COS:Minlnstances.срр {0} linclude OurMin.cpp Специализации для int и double template const int& min<int>(const int&. const int&); template const doubles min<double>(const doubles, const doubles); III:- Чтобы вручную сгенерировать конкретную специализацию шаблона, перед объявлением специализации ставится ключевое слово template. Учтите, что в данном случае вместо OurMin.h необходимо включить файл OurMin.cpp, поскольку для построения специализаций компилятору необходимо определение шаблона. Впрочем, в других местах это делать не придется, поскольку необходимые уникальные специализации min() уже получены, и для остальных файлов объявлений доста- точно. Так как файл OurMin.cpp включается средствами препроцессора, также следует добавить защитные директивы: : С05:OurMin.cpp {0} fifndef OURMIN CPP fdefine OURMIN CPP findude OurMin.h tempiate<typename T> const T& min(const T& a. const T& b) { return (a < b) ? a : b: fendif /:- OURMIN CPP /.- Если теперь откомпилировать все файлы, уникальные специализации min() будут успешно найдены, и программа выведет правильный результат: Явная специализация также может потребоваться для классов и статических переменных. При явном объявлении специализации класса автоматически генерируются все функции класса этой специализации, кроме тех, которые были явно сгенерированы ранее. Это важно, поскольку при использовании этого механизма становятся бесполезными многие шаблоны, а конкретно шаблоны, реализующие разную функциональность в зависимости от типов своих параметров. Неявная специализация здесь обладает преимуществами: при ней генерируются только вызываемые функции. Механизм явной специализации предназначен для больших проектов, в которых он позволяет существенно сократить время компиляции. Впрочем, выбор между явной и неявной специализациями не зависит от используемой модели компиляции шаблонов. Явная специализация может применяться как в модели с включением, так и в модели с разделением (см. следующий раздел). Модель с разделением В модели компиляции шаблонов с разделением определения шаблонных функций или статических переменных классов отделяются от их объявлений и переносятся в другие единицы трансляции, как это обычно делается с обычными функциями и данными. Для этой цели используется экспорт шаблонов. После знакомства с двумя предыдущими разделами это может показаться странным. Зачем было вводить модель с включением, если можно было просто сохранить существующий порядок вещей? Причины имеют как исторический, так и технический характер. Исторически модель с включением первой получила широкое коммерческое распространение. В наши дни все компиляторы С++ поддерживают модель с включением. Отчасти это объясняется тем, что нормальная спецификация модели с разделением появилась лишь на поздней стадии процесса стандартизации, а также тем, что модель с включением проще реализуется. Множество работоспособных программ было написано задолго до приведения семантики модели с разделением к окончательному виду. С реализацией модели с разделением возникает столько трудностей, что летом 2003 года она поддерживалась только одним компилятором (внешним интерфейсом EDG). Более того, она продолжает требовать, чтобы исходный текст шаблона был доступен на стадии компиляции. Требование о наличии исходных текстов планируется заменить некоторой формой промежуточного кода, что позволит распространять заранее откомпилированные шаблоны без исходных текстов. Из-за отмеченных ранее сложностей поиска (поиска зависимых имен в контексте определения шаблона) полное определение должно быть доступно в той или иной форме при компиляции программы, в которой этот шаблон специализируется. Синтаксис отделения исходного кода определения шаблона от его объявления достаточно прост. Это делается при помоши ключевого слова export: : C05:OurM1n2.h Объявление min как экспортированного шаблона (работает только в компиляторах на базе EDG) #ifndef 0URMIN2 H #define 0URMIN2 H Объявление min export tempiate<typename T> const T& m1n(const T&. const T&): #endif /:- 0URMIN2 H /:- Ключевое слово export no аналогии с inline или virtual должно присутствовать в потоке компиляции только один раз при первом упоминании экспортируемого шаблона. По этой причине повторять его в файле реализации не обязательно, хотя это рекомендуется: С05:ОигМ1п2.срр Определение экспортированного шаблона min (работает только в компиляторах на базе EDG) linclude OurMin2.h export tempiate<typename T> const T& min(const T& a. const T& b) { return (a < b) ? a : b: } III:- Остается лишь включить в фа11лы UseMin правильный заголовочный файл (0urMin2.h), а главная программа остается неизменной. Хотя на первый взгляд такой подход обеспечивает полноценное разделение, файл с определением шаблона (0urMin2.cpp) все равно должен поставляться пользователям (поскольку он должен обрабатываться для каждой специализации min()) до тех пор, пока не появится какая-либо форма представления промежуточного кода шаблона. Таким образом, хотя стандарт позволяет отделить объявление шаблона от определения, не все преимушества такого разделения доступны сегодня. Ключевое слово export сейчас поддерживается лишь одним семейством компиляторов (на базе внешнего интерфейса EDG), причем эти компиляторы сейчас не обеспечивают потенциальную возможность распространения определений шаблонов в откомпилированной форме. Итоги Возможности шаблонов далеко выходят за рамки простой параметризации по типам. В сочетании с автоматическим определением типов аргументов, переопределением специализаций и метапрограммированием шаблоны С++ превращаются в мощный механизм генерирования программного кода. Среди недостатков шаблонов С++, о которых в этой главе не упоминалось, стоит упомянуть трудности с интерпретацией сообщений об ошибках компиляции;
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |