Параметр типа шаблона применим как тип нескольких параметров функции. Поскольку набор преобразований ограничен, аргументы таких параметров должны быть, по существу, того же типа. Если выведенные типы не совпадают, то вызов ошибочен. Например, функция compare()
(см. раздел 16.1.1) получает два параметра const Т&
. У ее аргументов должен быть фактически тот же тип:
long lng;
compare(lng, 1024); //
//
Этот вызов ошибочен потому, что у аргументов функции compare()
не совпадают типы. Для первого аргумента выведен аргумент шаблона типа long
; а для второго — int
. Эти типы не совпадают, поэтому дедукция аргумента шаблона терпит неудачу.
Если необходимо обеспечить обычные преобразования аргументов, можно определить функцию с двумя параметрами типа:
//
template
int flexibleCompare(const A& v1, const B& v2) {
if (v1 < v2) return -1;
if (v2 < v1) return 1;
return 0;
}
Теперь пользователь может предоставлять аргументы разных типов:
long lng;
flexibleCompare(lng, 1024); //
Конечно, должен существовать оператор <
, способный сравнивать значения этих типов.
У шаблона функции могут быть параметры, определенные с использованием обычных типов, т.е. типов, которые не задействуют параметр типа шаблона. Такие аргументы не обрабатываются специальным образом; они преобразуются, как обычно, в соответствующий тип параметра (см. раздел 6.1). Рассмотрим, например, следующий шаблон:
template
return os << obj;
}
Тип первого параметра функции известен: ostream&
. У второго параметра, obj
, тип параметра шаблона. Поскольку тип параметра os
фиксирован, при вызове функции print()
к переданным ему аргументам применимы обычные преобразования:
print(cout, 42); //
ofstream f("output");
print(f, 10); //
//
В первом вызове тип первого аргумента точно соответствует типу первого параметра. Этот вызов задействует ту версию функции print()
, которая получает тип ostream&
и тип int
для создания экземпляра. Во втором вызове первый аргумент имеет тип ofstream
, а преобразование из ofstream
в ostream&
допустимо (см. раздел 8.2.1). Поскольку тип этого параметра не зависит от параметра шаблона, компилятор неявно преобразует f
в ostream&
.
Упражнение 16.32. Что происходит при дедукции аргумента шаблона?
Упражнение 16.33. Назовите два преобразования типов, допустимых для аргументов функций, при дедукции аргумента шаблона.
Упражнение 16.34. С учетом только следующего кода объясните, допустим ли каждый из этих вызовов. Если да, то каков тип Т
? Если нет, то почему?
template
(a) compare("hi", "world"); (b) compare("bye", "dad");
Упражнение 16.35. Какой из следующих вызовов ошибочен (если он есть)? Каков тип Т
допустимых вызовов? В чем проблема недопустимых вызовов?
template
template
double d; float f; char с;
(a) calc(с, 'c'); (b) calc(d, f);
(c) fcn(c, 'c'); (d) fcn(d, f);
Упражнение 16.36. Что происходит при следующих вызовах:
template
template
int i = 0, j = 42, *p1 = &i, *p2 = &j
const int *cp1 = &i, *cp2 = &j
(a) f1(p1, p2); (b) f2(p1, p2); (c) f1(cp1, cp2);
(d) f2(cp1, cp2); (e) f1(p1, cp1); (e) f2(p1, cp1);
В некоторых редких случаях компилятор не может вывести типы аргументов шаблона. В других случаях следует позволить пользователю контролировать создание экземпляра шаблона. Оба эти случая наиболее вероятны тогда, когда тип возвращаемого значения функции отличается от типов используемых ею параметров.