Вступление
Шаблонные функции и классы служат аналогичной цели в C ++, так как дженерики служат в C #. Они позволяют вам повторно использовать ваш код без написания функции или класса для каждого варианта, который вы хотите. Пока типы, которые вы предоставляете шаблону, имеют связанные с ними функциональные возможности, которые использует шаблон, все в порядке. Если нет, то компилятор выдаст ошибку. Это потому, что компилятор генерирует уникальный класс для каждой используемой вами специализации. Поскольку компилятор создает классы и функции из шаблонов вашей программы, шаблонные функции и классы должны быть помещены в заголовочные файлы и определены полностью встроенными. Таким образом, компилятор может анализировать их для всех файлов исходного кода, которые их используют.
В конечном итоге шаблоны могут стать очень сложными. Стандартная библиотека C ++ демонстрирует мощь и сложность расширенных шаблонов. Несмотря на это, вам не нужны глубокие знания шаблонов для их эффективного использования. Понимание основ шаблонов C ++ поможет вам раскрыть значительный объем функциональности и мощности.
Функции шаблона
Функция шаблона — это отдельная функция, которая принимает как минимум один аргумент шаблона. Тот факт, что он принимает аргумент, делает его неполным до тех пор, пока он не будет вызван с конкретным аргументом, в результате чего шаблон становится полностью определенной функцией. Вот шаблонная функция, которая принимает два аргумента.
Образец: TemplatesSample \ PeekLastItem.h
1
2
3
4
5
6
7
|
#pragma once
template<class T, class U>
U PeekLastItem(T& collection)
{
return *collection.rbegin();
}
|
Создание любого шаблона — функции или класса — начинается с ключевого слова template, за которым следуют параметры в квадратных скобках, как показано в предыдущем примере с классом T и классом U. Использование слова class перед T и U не означает аргументы должны быть классами. Вместо этого думайте о классе как об общем слове, предназначенном для передачи значения неспецифического типа. У вас может быть шаблон с конкретными типами или со смесью неспецифических типов классов и конкретных типов, таких как template<class T, int>
. Использование T в качестве имени для первого аргумента и U для второго — обычная практика, а не требование. Вы можете использовать почти что угодно в качестве имени аргумента шаблона.
Предыдущая функция принимает ссылку на элемент типа T. Предполагается, что T будет иметь функцию-член с именем rbegin
, которая может быть вызвана без аргументов, и будет возвращать тип указателя, который при rbegin
ссылки станет объектом типа U. Эта конкретная функция предназначена в первую очередь для работы со многими классами коллекций стандартной библиотеки C ++, хотя любой класс, который соответствует предположениям, которые делает функция в отношении типа T, может использоваться с этой функцией шаблона. Эта способность принимать любой тип, добавлять к нему необходимые функциональные возможности и, таким образом, делать его пригодным для использования с шаблоном, является основным преимуществом шаблонов.
Шаблоны классов
Шаблонные классы похожи на шаблонные функции, только они являются классами, а не простыми автономными функциями. Давайте посмотрим на пример.
Образец: TemplatesSample \ SimpleMath.h
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
#pragma once
template<class T>
class SimpleMath
{
public:
SimpleMath(void) { }
~SimpleMath(void) { }
T Add(T a, T b)
{
return a + b;
}
T Subtract(T a, T b)
{
return a — b;
}
T Multiply(T a, T b)
{
return a * b;
}
T Divide(T a, T b)
{
return a / b;
}
};
|
Как следует из названия, этот класс не предназначен для демонстрации. Существует только один тип аргумента. Глядя на определение класса, мы можем сделать вывод, что требования для T в этом случае состоят в том, что он имеет следующие операторы, каждый из которых работает с двумя экземплярами T и возвращает экземпляр T:
- +
- —
- *
- /
Хотя они логически связаны с числами, вы можете определить эти операторы для любого класса или типа данных, а затем создать экземпляр этого класса-шаблона, который специализирован для вашего пользовательского класса (например, класса Matrix).
И последнее замечание: если бы вы определяли функции-члены вне определения класса, но все же находились в том же заголовочном файле, конечно, вам нужно было бы использовать ключевое слово inline в объявлениях; определения будут выглядеть так: SimpleMath::SimpleMath(void) { }
.
Это последний файл этого примера, показывающий простое использование каждого из предыдущих шаблонов.
Образец: TemplatesSample \ TemplatesSample.cpp
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
#include <iostream>
#include <ostream>
#include <vector>
#include «SimpleMath.h»
#include «PeekLastItem.h»
#include «../pchar.h»
using namespace std;
int _pmain(int /*argc*/, _pchar* /*argv*/[])
{
SimpleMath<float> smf;
wcout << «1.1F + 2.02F = » << smf.Add(1.1F, 2.02F) << «F.»
endl;
vector<const wchar_t*> strs;
strs.push_back(L»Hello»);
strs.push_back(L»World»);
wcout << L»Last word was ‘» <<
PeekLastItem<std::vector<const wchar_t*>,const wchar_t*>(strs) <<
L»‘.»
return 0;
}
|
Вывод
Функции шаблонов помогают вам повторно использовать код, что, в свою очередь, делает вашу базу кода более легкой в управлении и СУХОЙ (не повторяйте себя). Лямбда-выражения являются предметом следующей статьи этой серии.
Этот урок представляет собой главу из C ++ Succinctly , бесплатной книги от команды Syncfusion .