Выбрать главу

template class Type

class ArrayRC : public ArrayType { /* ... */ };

int main() {

ArrayRCint ia_rc(10);

min4( ia_rc );

}

Фактический аргумент ia_rc имеет тип ArrayRCint. Он не совпадает с типом формального параметра ArrayType. Но одним из базовых классов для ArrayRCint является Arrayint, так как он конкретизирован из шаблона класса, указанного в качестве формального параметра функции. Поскольку фактический аргумент является производным классом, то его можно использовать при выводе аргументов шаблона. Таким образом, перед выводом аргумент функции ArrayRCint преобразуется в тип Arrayint, после чего для аргумента шаблона Type выводится тип int и конкретизируется функция min4(Arrayint).

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

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. Аргумент шаблона T, выведенный из первого аргумента функции, – это int. Аргумент же шаблона T, выведенный из второго аргумента функции, – это unsigned int. Поскольку они оказались разными, процесс вывода завершается неудачей и при конкретизации шаблона выдается сообщение об ошибке. (Избежать ее можно, если явно задать аргументы шаблона при вызове функции min5(). В разделе 10.4 мы увидим, как это делается.)

Ограничение на допустимые типы преобразований относится только к тем фактическим параметрам функции, которые принимают участие в выводе аргументов шаблона. К остальным аргументам могут применяться любые трансформации. В следующем шаблоне функции sum() есть два формальных параметра. Фактический аргумент op1 для первого параметра участвует в выводе аргумента Type шаблона, а второй фактический аргумент op2 – нет.

template class Type

Type sum( Type op1, int op2 ) { /* ... */ }

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

int ai[] = { ... };

double dd;

int main() {

// конкретизируется sum( int, int )

sum( ai[0], dd );

}

Тип второго фактического аргумента функции dd не соответствует типу формального параметра int. Но это не мешает конкретизировать шаблон функции sum(), поскольку тип второго аргумента фиксирован и не зависит от параметров шаблона. Для этого вызова конкретизируется функция sum(int,int). Аргумент dd приводится к типу int с помощью преобразования целого типа в тип с плавающей точкой.

Таким образом, общий алгоритм вывода аргументов шаблона можно сформулировать следующим образом:

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

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

* Тип фактического аргумента функции не обязан точно соответствовать типу формального параметра. Для приведения типов могут быть применены следующие преобразования: трансформации l-значения

* преобразования спецификаторов

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

*

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

Упражнение 10.4

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

Упражнение 10.5

Пусть даны следующие определения шаблонов:

template class Type

Type min3( const Type* array, int size ) { /* ... */ }

template class Type