- •Цель работы
- •2 Техническое обеспечение
- •3 Программное обеспечение
- •4 Постановка задачи
- •Общие сведения
- •5.1 Шаблоны классов
- •5.1.1 Пример класса-шаблона
- •5.1.2 Параметры шаблона, задаваемые по умолчанию
- •5.1.3 Специализация шаблона класса
- •5.1.4 Статические элементы в шаблонах
- •5.1.5 Шаблоны классов с шаблонами
- •5. 2 Шаблоны функций
- •5.3 Обобщенные алгоритмы и функторы
- •Варианты заданий
- •7 Указания к выполнению лабораторной работы
- •9 Контрольные вопросы
5. 2 Шаблоны функций
Помимо определения шаблонов классов, С++ разрешает писать шаблоны функций. Синтаксис шаблона функции следующий:
template <параметры>
заголовок
{ тело }
Параметры шаблона функции могут быть такими же, как и параметры шаблона-класса. В шаблонах функций тоже разрешено использовать параметры, не являющиеся типами; параметр-тип можно задавать как в качестве типа аргументов функции, так и в качестве типа возвращаемого значения. Например, шаблон функции поиска минимального значения в массиве может быть таким:
template <typename Т>
Т Min(T const *begin, Т const *end)
{
T min = *begin;
while (begin != end) if (min > *(++begin)) min = *begin;
return min;
}
Вызов этой функции-шаблона выглядит как вызов обычной функции:
int а[10]= {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
cout << Min(a, а+10) << endl;// выбор минимума из массива int
double b[10]= {1.1, 2, 3, 4, 5, 6, 7, 8, 9,10.1};
cout << Min(b, b+10) << endl;// выбор минимума из массива double
При вызове шаблона-функции не заданы аргументы шаблона в угловых скобках о. Компилятор самостоятельно подставляет тип на основании информации о типе фактического аргумента при вызове. Для шаблонов классов аргументы нужно задавать всегда явно. Явное указание аргументов можно делать и при вызове функции-шаблона, например:
cout << Min<int>(a, а+10) << endl;// выбор минимума из массива int
cout << Min<double>(b, b+10) << endl;
Вывод типов не работает для типа возвращаемого значения такой аргумент при вызове функции-шаблона всегда нужно указывать явно. Поэтому, если требуется, чтобы тип возвращаемого значения тоже был параметром шаблона, следует ставить его на первую позицию списка.
template <class RT, class Т>
RT Multiply(Т const *begin, T const *end)
{
RT total = 1:
while (begin != end)
{
total *= *begin;
++begin;
}
return total;
}
Теперь вызовы нужно писать с явным указанием аргумента для типа возвращаемого значения, например:
int а[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
cout << Multiply<long>(a, а+10) << endl;
double b[10] = {1.1, 2, 3, 4, 5, 6, 7, 8, 9,10.1};
cout << Multiply<double>(b, b+10) << endl;
Типы параметров функции компилятор выясняет самостоятельно. Попытка вызвать функцию-шаблон без аргумента, наподобие
cout << Multiply(b, b+10) << endl;
приводит к ошибке трансляции.
Параметры, не являющиеся типами, компилятор обычно не может идентифицировать сам, поэтому их, как правило, надо указывать явно. Например, шаблон функции инициализации числового массива может быть таким:
template <std::size_t N, class Т, Т t>
void Init(T array[N]) // передача массива
{
for(std::size_t i =0; i<N; ++i)
array[i] = t;
}
Вызов этой функции требует задания всех аргументов шаблона:
int а[100];
Init<100, int, 3>(а);
Перегрузка и специализация шаблонов функций
Допускается перегрузка функций-шаблонов шаблонами и обычными функциями. Как и при перегрузке обычных функций, шаблоны (и функции) должны отличаться списками параметров. Компилятор при обработке конкретного вызова старается подобрать наиболее подходящий вариант.
Помимо перегрузки, для шаблонов функций реализован механизм полной специализации. Частичная специализация для функций-шаблонов запрещена. Например, функция max() с параметрами-указателями на символы, шаблон и специализация шаблона с параметрами-указателями выглядят так:
char *max(const char *х, const char *y) // функция
{ return (strcmp(x, y) > 0) ? x : y; }
template <typename T> // шаблон
T const &max(T const &x, T const &y)
{ return (x > y) ? x : y; }
template <> // специализация шаблона
char* const &max(char *const &x, char* const &y)
{ return (strcmp(x, y) > 0) ? x : y; }
Специализация начинается с ключевого слова template с пустыми угловыми скобками. Вообще говоря, для полной специализации требуется задавать специализирующие аргументы после имени шаблона:
template<> // специализация шаблона
char* const &max<char*>(char* const &x, char* const &y)
{ return (strcmp(x, y) > 0) ? x : y; }
Но для шаблонов функций это практически всегда необязательно, поскольку компилятор способен выяснить тип самостоятельно.
Параметры по умолчанию
В шаблонах функций нельзя задавать параметры по умолчанию. Однако это ограничение легко обойти, используя класс-обертку. В листинге 11.5 такая функция является статическим методом класса.
Листинг 11.5. Класс-обертка шаблона функции
template <class RT = double, class T = float>
class Function
{
public:
static RT Multiply(T const *begin, T const *end)
{
RT total = 1;
while (begin != end)
{
total *= *begin;
++begin;
}
return total;
}
};
Вызов функции должен сопровождаться префиксом класса-шаблона.
float f[10] = {1.1, 2, 3, 4, 5, 6, 7, 8, 9, 10.1};
cout << Function<>::Multiply(f, f+10) << endl;
int L[10]= {1, 2, 3, 4, 5,6, 7, 8, 9, 10};
cout << Functional<float, int>: :Multiply(L, L+10) << endl;
