Глава 5. Продвинутые концепции #
5.1 Шаблоны в C++ #
Шаблоны являются мощным механизмом обобщенного программирования в C++, позволяющим создавать универсальный код, работающий с различными типами данных.
1. Функции-шаблоны #
1.1 Базовый синтаксис #
// Шаблонная функция для обмена значений
template <typename T>
void swap(T& a, T& b) {
T temp = a;
a = b;
b = temp;
}
int main() {
int x = 5, y = 10;
swap(x, y); // Работает с int
double a = 3.14, b = 2.71;
swap(a, b); // Работает с double
return 0;
}
1.2 Ключевые особенности #
- Ключевое слово
template
- Параметр типа указывается с
typename
илиclass
- Компилятор автоматически генерирует код для каждого используемого типа
1.3 Функции с несколькими параметрами типа #
template <typename T1, typename T2>
void printPair(T1 first, T2 second) {
std::cout << "First: " << first
<< ", Second: " << second << std::endl;
}
int main() {
printPair(42, "Hello"); // int и const char*
printPair(3.14, std::string("Pi")); // double и string
return 0;
}
2. Классы-шаблоны #
2.1 Определение шаблонного класса #
template <typename T>
class Stack {
private:
std::vector<T> elements;
public:
void push(const T& item) {
elements.push_back(item);
}
T pop() {
if (!elements.empty()) {
T top = elements.back();
elements.pop_back();
return top;
}
throw std::out_of_range("Стек пуст");
}
bool isEmpty() const {
return elements.empty();
}
};
int main() {
Stack<int> intStack;
intStack.push(10);
intStack.push(20);
Stack<std::string> stringStack;
stringStack.push("Привет");
stringStack.push("Мир");
return 0;
}
2.2 Параметры по умолчанию #
template <typename T = int>
class Container {
private:
T value;
public:
Container(T val = T()) : value(val) {}
};
int main() {
Container<> defaultContainer; // int по умолчанию
Container<double> doubleContainer; // double
return 0;
}
3. Шаблоны с несколькими параметрами #
3.1 Сложные шаблонные конструкции #
template <typename K, typename V>
class Map {
private:
std::vector<std::pair<K, V>> data;
public:
void insert(const K& key, const V& value) {
data.push_back({key, value});
}
V& operator[](const K& key) {
for (auto& item : data) {
if (item.first == key) {
return item.second;
}
}
// Вставка нового элемента, если ключ не найден
data.push_back({key, V()});
return data.back().second;
}
};
int main() {
Map<std::string, int> ages;
ages.insert("Алиса", 30);
ages["Боб"] = 25;
Map<int, std::string> names;
names.insert(1, "Первый");
names[2] = "Второй";
return 0;
}
3.2 Ограничения и требования к типам #
// Шаблонная функция с ограничением на копируемость
template <typename T>
requires std::copyable<T>
T duplicateValue(const T& value) {
return value;
}
4. Специализация шаблонов #
4.1 Полная специализация #
// Общий шаблон
template <typename T>
class Printer {
public:
void print(const T& value) {
std::cout << "Общий шаблон: " << value << std::endl;
}
};
// Полная специализация для bool
template <>
class Printer<bool> {
public:
void print(bool value) {
std::cout << "Специализация для bool: "
<< (value ? "true" : "false") << std::endl;
}
};
int main() {
Printer<int> intPrinter;
intPrinter.print(42); // Общий шаблон
Printer<bool> boolPrinter;
boolPrinter.print(true); // Специализация для bool
return 0;
}
4.2 Частичная специализация #
// Общий шаблон для указателей
template <typename T>
class Pointer {
public:
static void print(T* ptr) {
std::cout << "Указатель: " << ptr << std::endl;
}
};
// Частичная специализация для указателей на char
template <typename T>
class Pointer<T*> {
public:
static void print(T* ptr) {
std::cout << "Указатель на объект: "
<< *ptr << std::endl;
}
};
int main() {
int x = 42;
int* ptr = &x;
Pointer<int*>::print(ptr); // Вызовет специализированную версию
return 0;
}
Заключение #
Ключевые преимущества шаблонов #
- Типобезопасность
- Возможность создания обобщенного кода
- Генерация кода во время компиляции
- Минимальные накладные расходы времени выполнения
Рекомендации #
- Используйте шаблоны для создания универсальных алгоритмов и структур данных
- Будьте осторожны с усложнением шаблонов
- Применяйте специализацию для оптимизации под конкретные типы
- Следите за читаемостью кода при использовании сложных шаблонов
Типичные ошибки #
- Чрезмерное использование шаблонов
- Сложночитаемые многопараметрические шаблоны
- Неправильная специализация
- Большой объем сгенерированного кода
Дополнительные материалы #
- С++ Standard Template Library (STL)
- Концепты в современном C++ (C++20)
- SFINAE и метапрограммирование