Шаблоны функций


Кроме шаблонов классов мы можем применять шаблоны функций (function template). Например, рассмотрим следующий пример:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>

int add(int x, int y)
{
return x + y;
}
double add(double x, double y)
{
return x + y;
}
int main()
{
double n1 = add(4.7, 5.3); // 10
int n2 = add(4, 5); // 9

std::cout << "n1: " << n1 << std::endl;
std::cout << "n2: " << n2 << std::endl;

return 0;
}
Данный пример отлично работает, производит вычисления, как и должен. Однако в данном случае мы сталкиваемся с тем, что функция add фактически дублируется. Обе ее версии фактически выполняют одно и то же действие, единственно что отличается тип параметров и возвращаемого значения: в одном случае это тип int, а в другом - тип double.

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <iostream>

template<typename T>
T add(T x, T y)
{
return x + y;
}
int main()
{
double a1 = 4.7, b1 = 5.3;
double n1 = add(a1, b1);

int a2 = 4, b2 = 5;
int n2 = add(a2, b2);

short a3 = 3, b3 = 2;
short n3 = add(a3, b3);

std::cout << "n1: " << n1 << std::endl;
std::cout << "n2: " << n2 << std::endl;
std::cout << "n3: " << n3 << std::endl;

return 0;
}
Определение шаблона функции, как и шаблона класса, начинается с ключевого слова template, после которого указываются угловые скобки. В угловых скобках после слова typename идет параметр шаблона. Можно определить несколько параметров шаблона, в примере выше применяется только один параметр.

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

И при вызове функции add в нее можно передавать объекты и типа int, и типа double, и любого другого типа. При вызове функции компилятор на основании типа аргументов выведет конкретный тип, связанный с параметром шаблона T.

Другой пример - функция обмена значениями:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <iostream>

template <typename T>
void swap(T& a, T& b)
{
T temp = a;
a = b;
b = temp;
}

int main()
{
int c = 30;
int d = 10;
swap(c, d);
std::cout << "c = " << c << "\t d = " << d << std::endl;

return 0;
}
Функция swap принимает два параметра любого типа и меняет их значения.

Можно использовать несколько параметров:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream>
#include <string>

template <typename T, typename K>
void transact(T fromAcc, T toAcc, K code, int sum)
{
std::cout << "From: " << fromAcc << "\nTo: " << toAcc
<< "\nSum: " << sum << "\nCode: " << code << std::endl;
}

int main()
{
transact("id1234", "id5678", 2804, 5000);

return 0;
}
В данном случае при вызове transact("id1234", "id5678", 2804, 5000); вместо параметра T будет подставляться тип string, а вместо параметра K - тип int.