-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathtemplates-basic.cpp
77 lines (60 loc) · 3.92 KB
/
templates-basic.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
#include <iostream>
/// Создавая шаблонизированный класс, мы фактически создаём не один класс,
/// а целое семейство классов.
/// То есть конкретный класс -- это семейство возможных его значений,
/// а шаблонный класс -- это семейство возможных его конкретных классов.
/// Такой подход называется метапрограммированием -- когда мы создаём
/// шаблоны для компилятора, по которым он сам генерирует код
/// в привычном понимании, после чего компилирует этот сгенерированный код.
/// Важно понимать, что генерация и подстановки всех вызовов происходят
/// во время компиляции. То есть вся концепция статическая, а не динамическая.
/// Шаблонизировать можно классы и функции.
/// Шаблонизировать можно по типам, целочисленным значениям
/// (bool -- тоже целочисленный), по функциям и не только.
/// По числам с плавающей точкой -- нельзя.
/// После знака "=" можно задать шаблонный аргумент по умолчанию --
/// идея такая же, как и с аргументами по умолчанию у функций.
template<typename Ttype, int Tint, bool Tbool = false>
class A {
public:
/// Это такой способ связать с конкретной инстанциацией шаблонного
/// класса (то есть с конкретным типом) известное во время компиляции
/// целочисленное значение. Получить его в других местах можно через "::"
static const int I = Tint;
static const bool B = Tbool;
/// Аналогично -- связываем с типом некий другой тип
typedef Ttype Type;
private:
/// Значение I известно во время компиляции -- что позволяет использовать
/// его, к примеру, как размер статического массива
Type array[I];
};
/// Частичная специализация класса для конкретного значения шаблонного аргумента.
/// То есть если где-то в коде появится запрос на создание класса с такими
/// параметрами (с нулевым int'ом в данном случае),
/// будет сгенерирована эта реализация, а не та, что сверху.
template<typename Ttype, bool Tbool>
class A<Ttype, 0, Tbool> {
public:
static const int I = 0;
static const bool B = Tbool;
typedef Ttype Type;
private:
/// Массивы нулевой длины запрещены
};
int main() {
/// Каждый раз компилятор будет создавать новый конкретный класс
/// по нашему требованию в коде. Это три *разных* класса:
A<float, 15, true> f15true;
A<double, 6> d6false;
typedef A<char, 0> ACharZero;
ACharZero c0false;
/// "static const" значения относятся к типу,
/// а не к конкретному объекту. То есть мы можем написать и так:
std::cout << c0false.B << std::endl;
/// и так:
std::cout << ACharZero::B << std::endl;
/// Ошибка при компиляции "size of array is negative"
// A<size_t, -1> invalid;
return 0;
}