double da[6] = { 10.2, 7.1, 14.5, 3.2, 25.0, 16.8 };
#include iostream
int main()
{
// конкретизация min() для массива из 5 элементов типа int
// подставляется Type = int, size = 5
int i = min( ia );
if ( i != 3 )
cout "??oops: integer min() failed\n";
else cout "!!ok: integer min() worked\n";
// конкретизация min() для массива из 6 элементов типа double
// подставляется Type = double, size = 6
double d = min( da );
if ( d != 3.2 )
cout "??oops: double min() failed\n";
else cout "!!ok: double min() worked\n";
return 0;
}
Вызов
int i = min( ia );
приводит к конкретизации следующего экземпляра функции min(), в котором Type заменено на int, а size на 5:
int min( int (r_array)[5] )
{
int min_val = r_array[0];
for ( int i = 1; i 5; ++i )
if ( r_array[i] min_val )
min_val = r_array[i];
return min_val;
}
Аналогично вызов
double d = min( da );
конкретизирует экземпляр min(), в котором Type заменено на double, а size на 6:
В качестве формальных параметров шаблона функции используются параметр-тип и параметр-константа. Для определения фактического типа и значения константы, которые надо подставить в шаблон, исследуются фактические аргументы, переданные при вызове функции. В нашем примере для идентификации аргументов шаблона при конкретизации используются тип ia (массив из пяти int) и da (массив из шести double). Процесс определения типов и значений аргументов шаблона по известным фактическим аргументам функции называется выведением (deduction) аргументов шаблона. (В следующем разделе мы расскажем об этом подробнее. А в разделе 10.4 речь пойдет о возможности явного задания аргументов.)
Шаблон конкретизируется либо при вызове, либо при взятии адреса функции. В следующем примере указатель pf инициализируется адресом конкретизированного экземпляра шаблона. Его аргументы определяются путем исследования типа параметра функции, на которую указывает pf:
template typename Type, int size
Type min( Type (p_array)[size] ) { /* ... */ }
// pf указывает на int min( int ()[10] )
int (*pf)(int ()[10]) = min;
Тип pf – это указатель на функцию с параметром типа int()[10], который определяет тип аргумента шаблона Type и значение аргумента шаблона size при конкретизации min(). Аргумент шаблона Type будет иметь тип int, а значением аргумента шаблона size будет 10. Конкретизированная функция представляется как min(int()[10]), и указатель pf адресует именно ее.
Когда берется адрес шаблона функции, контекст должен быть таким, чтобы можно было однозначно определить типы и значения аргументов шаблона. Если сделать это не удается, компилятор выдает сообщение об ошибке:
template typename Type, int size
Type min( Type (r_array)[size] ) { /* ... */ }
typedef int (rai)[10];
typedef double (rad)[20];
void func( int (*)(rai) );
void func( double (*)(rad) );
int main() {
// ошибка: как конкретизировать min()?
func( min );
}
Функция func() перегружена и тип ее параметра не позволяет однозначно определить ни аргумент шаблона Type, ни значение аргумента шаблона size. Результатом конкретизации вызова func() может быть любая из следующих функций:
min( int (*)(int()[10]) )
min( double (*)(double()[20]) )
Поскольку однозначно определить аргументы функции func() нельзя, взятие адреса конкретизированного шаблона в таком контексте приводит к ошибке компиляции.
Этого можно избежать, если использовать явное приведение типов для указания типа аргумента:
int main() {
// правильно: с помощью явного приведения указывается тип аргумента
func( static_cast double(*)(rad) (min) );
}
Лучше, однако, применять явное задание аргументов шаблона, как будет показано в разделе 10.4.
10.3. Вывод аргументов шаблона А