Шаблоны функций
В С++, так же как и для класса, для функции (глобальной, т.е. не являющейся компонентой-функцией) может быть описан шаблон. Это позволит снять достаточно жесткие ограничения, накладываемые механизмом формальных и фактических параметров при вызове функции. Рассмотрим это на примере функции, вычисляющей сумму нескольких аргументов.
#include <iostream>
using namespace std;
#include <string.h>
template <class T1,class T2>
T1 sm(T1 a,T2 b) // описание шаблона
{ return (T1)(a+b); // функции c двумя параметрами
}
template <class T1,class T2,class T3>
T1 sm(T1 a,T2 b,T3 c) // описание шаблона функции
{ return (T1)(a+b+c); // функции c тремя параметрами
}
int main()
{cout<<"вызов функции sm(int,int) = "<<sm(4,6)<<endl;
cout<<"вызов функции sm(int,int,int) = "<<sm(4,6,1)<<endl;
cout<<"вызов функции sm(int,double) = "<<sm(5,.3)<<endl;
cout<<"вызов функции sm(double,int,short)= " <<
sm(.4,6,(short)1)<<endl;
// cout<<sm("я изучаю","язык С++")<<endl; error cannot add two pointers
return 0;
}
Результат работы программы будет иметь вид:
вызов функции sm(int,int) = 10
вызов функции sm(int,int,int) = 11
вызов функции sm(int,double) = 5
вызов функции sm(double,int,short)= 7.4
В программе описана перегруженная функция sm(), первый экземпляр которой имеет 2, а второй 3 параметра. Тип формальных параметров функции определяется компилятором при каждой встрече вызова функции типом ее фактических параметров. Компилятор заменяет параметры T1,T2 (при вызове функции с двумя параметрами) или T1,T2,T3 (с тремя параметрами) на типы передаваемых в функцию значений. После этого полученная шаблонная функция компилируется. Используемые в функциях типы Т1, Т2, Т3 заданы как параметры для шаблона функции с помощью выражения template <class T1,class T2> или template <class T1,class T2,class T3>.
Имя каждого формального параметра заголовка шаблона может использоваться в заголовке только один раз. Одно и то же имя формального параметра шаблона может использоваться в нескольких заголовках шаблонов.
В случае попытки передачи в функцию sm() двух строк, т.е. типов, для которых не определена данная операция, компилятор выдаст ошибку. Чтобы избежать этого, можно ограничить использование шаблона функции sm(), описав явным образом функцию sm() для некоторых конкретных типов данных. В нашем случае:
char *sm(char *a,char *b) // явное описание функции объединения
{ char *tmp=a; // двух строк
a=new char[strlen(a)+strlen(b)+1];
strcpy(a,tmp);
strcat(a,b);
return a;
}
Добавление в main() инструкции, например,
cout<<sm("я изучаю"," язык С++")<<endl;
приведет к выводу кроме указанных выше сообщения:
я изучаю язык С++
Рассмотрим случай, когда имеются несколько шаблонов перегруженных функций с одинаковым числом аргументов.
template <class T1,class T2>
T1 sm(T1 a,T2 b) // описание шаблона первой
{ return (T1)(a+b); // функции c двумя параметрами
}
template <class T1,class T2>
T1 sm(T2 a,T1 b) // описание шаблона второй
{ return (T1)(a+b); // функции c двумя параметрами
}
int main()
{ sm(1.,2) // error 'sm' : none of 2 overload have a best conversion
// 'sm' : ambiguous call to overloaded function
return 0;
}
В этом случае компилятор должен сгенерировать оба экземпляра шаблонных функций. Возникает неоднозначность: какую из двух шаблонных функций требуется выполнить.
Шаблон функции может быть перегружен также, если описать другую (нешаблонную функцию), имя которой совпадает с именем шаблона функции.
Следует отметить, что шаблон функции не является ее экземпляром. Только при обращении к функции с аргументами конкретного типа происходит генерация конкретной функции.