|
Программирование >> Инициализация объектов класса, структура
template <class Type> class ArrayRC : public Array<Type> { /* ... */ }; int main() { ArrayRC<int> ia rc(10); min4( ia rc ); главе 2; наследование классов подробно рассматривается в главах 17 и 18.) Фактический аргумент ia rc имеет тин ArrayRC<int>. Он не совпадает с типом формального параметра Array<Type>&. Но одним из базовых классов для ArrayRC<int> является Array<int>, так как он конкретизирован из шаблона класса, указанного в качестве формального параметра функции. Поскольку фактический аргумент является производным классом, то его можно использовать при выводе аргументов шаблона. Таким образом, перед выводом аргумент функции ArrayRC<int> преобразуется в тип Array<int>, после чего для аргумента шаблона Type выводится тип int и конкретизируется функция min4(Array<int>&) . В процессе вывода одного аргумента шаблона могут принимать участие несколько аргументов функции. Если параметр шаблона встречается в списке параметров функции более одного раза, то каждый выведенный тип должен точно соответствовать типу, template <class T> T min5( T, T ) { /* unsigned int ui; */ } int main() { ошибка: нельзя конкретизировать min5( unsigned int, int ) должно быть: min5( unsigned int, unsigned int ) или min5( int, int ) min5( ui, 1024 ); выведенному для того же аргумента шаблона в первый раз: Оба фактических аргумента функции должны иметь один и тот же тип: либо int, либо unsigned int, поскольку в шаблоне они принадлежат к одному типу T. Аргумент template <class Type> class Array { /* ... */ } template <class Type> Type min4( Array<Type>& array ) Type min val = array[0]; for ( int i = 1; i < array.size(); ++i ) if ( array[i] < min val ) min val = array[i]; return min val; miin4() можно вызвать, передав в качестве первого аргумента ArrayRC<int>, как показано в следующем примере. (ArrayRC - это шаблон класса, также определенный в template <class Type> op2 - нет. Type sum( Type op1, int op2 ) { /* ... */ } Поэтому при конкретизации шаблона функции sum() его можно подвергать любым трансформациям. (Преобразования типов, применимые к фактическим аргументам int ai[] = { ... }; double dd; int main() { конкретизируется sum( int, int ) sum( ai[0], dd ); функции, описываются в разделе 9.3.) Например: Тип второго фактического аргумента функции dd не соответствует типу формального параметра int. Но это не мешает конкретизировать шаблон функции sum() , поскольку тип второго аргумента фиксирован и не зависит от параметров шаблона. Для этого вызова конкретизируется функция sum(int,int) . Аргумент dd приводится к типу int с помощью преобразования целого типа в тип с плавающей точкой. Таким образом, общий алгоритм вывода аргументов шаблона можно сформулировать следующим образом: 1. По очереди исследуется каждый фактический аргумент функции, чтобы выяснить, присутствует ли в соответствующем формальном параметре какой-нибудь параметр шаблона. 2. Если параметр шаблона найден, то путем анализа типа фактического аргумента выводится соответствующий аргумент шаблона. 3. Тип фактического аргумента функции не обязан точно соответствовать типу формального параметра. Для приведения типов могут быть применены следующие преобразования: трансформации 1-значения преобразования спецификаторов шаблона T, выведенный из первого аргумента функции, - это int. Аргумент же шаблона T, выведенный из второго аргумента функции, - это unsigned int. Поскольку они оказались разными, процесс вывода завершается неудачей и при конкретизации шаблона выдается сообщение об ошибке. (Избежать ее можно, если явно задать аргумента: шаблона при вызове функции miin5(). В разделе 10.4 м1 увидим, как это делается.) Ограничение на допустимые типы преобразований относится только к тем фактическим параметрам функции, которые принимают участие в выводе аргументов шаблона. К остальным аргументам могут применяться любые трансформации. В следующем шаблоне функции sum() есть два формальных параметра. Фактический аргумент op1 для первого параметра участвует в выводе аргумента Type шаблона, а второй фактический аргумент template <class Type> Type min3( const Type* array, int size ) { /* ... */ } template <class Type> Пусть даны следующие определения шаблонов: Type min5( Type p1, Type p2 ) { /* ... */ } double dobj1, dobj2; float fobj1, fobj2; char cobj1, cobj2; int ai[5] = { 511, 16, 8, 63, 34 }; (a) min5( cobj2, c ); (b) min5( dobj1, fobj1 ); Какие из приведенных ниже вызовов ошибочны? Почему? (c) min3( ai, cobj1 ); 10.4. Явное задание аргументов шаблона A В некоторых ситуациях автоматически вывести типы аргументов шаблона невозможно. Как мы видели на примере шаблона функции min5() , если процесс вывода дает два различных типа для одного и того же параметра шаблона, то компилятор сообщает об ошибке - неудачном выводе аргументов. В таких ситуациях приходится подавлять механизм вывода и задавать аргументы явно, указывая их с помощью заключенного в угловые скобки списка разделенных запятыми значений, который следует после имени конкретизируемого шаблона функции. Например, если мы хотим задать тип unsigned int в качестве значения аргумента шаблона T в рассмотренном выше примере использования miin5(), то нужно записать конкретизируется min5( unsigned int, unsigned int ) вызов конкретизируемого шаблона так: min5< unsigned int >( ui, 1024 ); приведение производного класса к базовому при условии, что формальный параметр функции имеет вид T<args>& или T<args>*, где список аргументов args содержит хотя бы один параметр шаблона. 4. Если один и тот же параметр шаблона найден в нескольких формальных параметрах функций, то аргумент шаблона, выведенный по каждому из соответствующих фактических аргументов, должен быть одним и тем же. Упражнение 10.4 Назовите два типа преобразований, которые можно применять к фактическим аргументам функций, участвующим в процессе вывода аргументов шаблона. Упражнение 10.5
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0.001
При копировании материалов приветствуются ссылки. |