C++ 模板
概述
模板(Template)是C++的强大特性,允许编写与类型无关的泛型代码。模板实现了编译时多态,提供了类型安全的代码重用机制。本章介绍函数模板、类模板、模板特化、SFINAE等高级模板技术。
🔧 函数模板
基础函数模板
cpp
#include <iostream>
#include <string>
#include <vector>
// 基础函数模板
template<typename T>
T max(T a, T b) {
return (a > b) ? a : b;
}
// 多参数模板
template<typename T, typename U>
auto add(T a, U b) -> decltype(a + b) {
return a + b;
}
// 非类型模板参数
template<typename T, int Size>
void printArray(const T (&arr)[Size]) {
std::cout << "数组大小: " << Size << ", 内容: ";
for (int i = 0; i < Size; ++i) {
std::cout << arr[i] << " ";
}
std::cout << std::endl;
}
// 变参模板
template<typename... Args>
void print(Args... args) {
((std::cout << args << " "), ...); // C++17折叠表达式
std::cout << std::endl;
}
int main() {
std::cout << "=== 函数模板 ===" << std::endl;
// 类型自动推导
std::cout << "max(3, 5) = " << max(3, 5) << std::endl;
std::cout << "max(3.14, 2.71) = " << max(3.14, 2.71) << std::endl;
std::cout << "max(\"hello\", \"world\") = " << max(std::string("hello"), std::string("world")) << std::endl;
// 显式指定类型
std::cout << "max<double>(3, 5.5) = " << max<double>(3, 5.5) << std::endl;
// 多类型模板
auto result = add(10, 3.14);
std::cout << "add(10, 3.14) = " << result << std::endl;
// 非类型参数
int arr[] = {1, 2, 3, 4, 5};
printArray(arr);
// 变参模板
print("Hello", 42, 3.14, "World");
return 0;
}模板特化
cpp
#include <iostream>
#include <string>
#include <vector>
// 主模板
template<typename T>
class Container {
private:
std::vector<T> data_;
public:
void add(const T& item) {
data_.push_back(item);
}
void print() const {
std::cout << "通用容器: ";
for (const auto& item : data_) {
std::cout << item << " ";
}
std::cout << std::endl;
}
size_t size() const { return data_.size(); }
};
// 全特化
template<>
class Container<bool> {
private:
std::vector<bool> data_;
public:
void add(bool item) {
data_.push_back(item);
}
void print() const {
std::cout << "布尔容器: ";
for (bool item : data_) {
std::cout << (item ? "true" : "false") << " ";
}
std::cout << std::endl;
}
size_t size() const { return data_.size(); }
};
// 偏特化
template<typename T>
class Container<T*> {
private:
std::vector<T*> data_;
public:
void add(T* item) {
data_.push_back(item);
}
void print() const {
std::cout << "指针容器: ";
for (const auto& ptr : data_) {
if (ptr) {
std::cout << *ptr << " ";
} else {
std::cout << "null ";
}
}
std::cout << std::endl;
}
size_t size() const { return data_.size(); }
};
int main() {
std::cout << "=== 模板特化 ===" << std::endl;
// 主模板
Container<int> intContainer;
intContainer.add(1);
intContainer.add(2);
intContainer.add(3);
intContainer.print();
// 全特化
Container<bool> boolContainer;
boolContainer.add(true);
boolContainer.add(false);
boolContainer.add(true);
boolContainer.print();
// 偏特化
Container<int*> ptrContainer;
int a = 10, b = 20, c = 30;
ptrContainer.add(&a);
ptrContainer.add(&b);
ptrContainer.add(&c);
ptrContainer.print();
return 0;
}🏗️ 类模板
基础类模板
cpp
#include <iostream>
#include <memory>
template<typename T>
class Stack {
private:
struct Node {
T data;
std::unique_ptr<Node> next;
Node(const T& value) : data(value), next(nullptr) {}
};
std::unique_ptr<Node> top_;
size_t size_;
public:
Stack() : top_(nullptr), size_(0) {}
// 移动构造函数
Stack(Stack&& other) noexcept
: top_(std::move(other.top_)), size_(other.size_) {
other.size_ = 0;
}
// 移动赋值运算符
Stack& operator=(Stack&& other) noexcept {
if (this != &other) {
top_ = std::move(other.top_);
size_ = other.size_;
other.size_ = 0;
}
return *this;
}
void push(const T& value) {
auto new_node = std::make_unique<Node>(value);
new_node->next = std::move(top_);
top_ = std::move(new_node);
++size_;
}
void pop() {
if (top_) {
top_ = std::move(top_->next);
--size_;
}
}
const T& top() const {
if (!top_) {
throw std::runtime_error("栈为空");
}
return top_->data;
}
bool empty() const { return top_ == nullptr; }
size_t size() const { return size_; }
};
// 模板成员函数
template<typename T>
class Vector {
private:
T* data_;
size_t size_;
size_t capacity_;
public:
Vector() : data_(nullptr), size_(0), capacity_(0) {}
~Vector() {
delete[] data_;
}
template<typename InputIt>
Vector(InputIt first, InputIt last) : Vector() {
while (first != last) {
push_back(*first++);
}
}
void push_back(const T& value) {
if (size_ == capacity_) {
reserve(capacity_ == 0 ? 1 : capacity_ * 2);
}
data_[size_++] = value;
}
void reserve(size_t new_capacity) {
if (new_capacity > capacity_) {
T* new_data = new T[new_capacity];
for (size_t i = 0; i < size_; ++i) {
new_data[i] = std::move(data_[i]);
}
delete[] data_;
data_ = new_data;
capacity_ = new_capacity;
}
}
T& operator[](size_t index) { return data_[index]; }
const T& operator[](size_t index) const { return data_[index]; }
size_t size() const { return size_; }
bool empty() const { return size_ == 0; }
};
int main() {
std::cout << "=== 类模板 ===" << std::endl;
// Stack测试
Stack<int> intStack;
intStack.push(1);
intStack.push(2);
intStack.push(3);
std::cout << "栈内容: ";
while (!intStack.empty()) {
std::cout << intStack.top() << " ";
intStack.pop();
}
std::cout << std::endl;
// Vector测试
Vector<std::string> strVector;
strVector.push_back("Hello");
strVector.push_back("World");
strVector.push_back("C++");
std::cout << "向量内容: ";
for (size_t i = 0; i < strVector.size(); ++i) {
std::cout << strVector[i] << " ";
}
std::cout << std::endl;
return 0;
}🔍 SFINAE和概念
SFINAE技术
cpp
#include <iostream>
#include <type_traits>
#include <string>
// SFINAE: Substitution Failure Is Not An Error
// 检测类型是否有begin()方法
template<typename T>
class has_begin {
private:
template<typename U>
static auto test(int) -> decltype(std::declval<U>().begin(), std::true_type{});
template<typename>
static std::false_type test(...);
public:
static constexpr bool value = decltype(test<T>(0))::value;
};
// 使用std::enable_if进行条件编译
template<typename T>
typename std::enable_if<std::is_arithmetic<T>::value, T>::type
process(T value) {
std::cout << "处理数值类型: " << value << std::endl;
return value * 2;
}
template<typename T>
typename std::enable_if<!std::is_arithmetic<T>::value, T>::type
process(T value) {
std::cout << "处理非数值类型: " << value << std::endl;
return value;
}
// 条件实例化
template<typename Container>
typename std::enable_if<has_begin<Container>::value>::type
printContainer(const Container& container) {
std::cout << "可迭代容器: ";
for (const auto& item : container) {
std::cout << item << " ";
}
std::cout << std::endl;
}
template<typename T>
typename std::enable_if<!has_begin<T>::value>::type
printContainer(const T& item) {
std::cout << "单个元素: " << item << std::endl;
}
int main() {
std::cout << "=== SFINAE技术 ===" << std::endl;
// 类型特征检测
std::cout << "std::vector<int> has begin(): " << has_begin<std::vector<int>>::value << std::endl;
std::cout << "int has begin(): " << has_begin<int>::value << std::endl;
// 条件编译
auto result1 = process(42);
auto result2 = process(std::string("Hello"));
std::cout << "处理结果: " << result1 << ", " << result2 << std::endl;
// 条件实例化
std::vector<int> vec = {1, 2, 3, 4, 5};
printContainer(vec);
printContainer(42);
return 0;
}📋 模板元编程
编译时计算
cpp
#include <iostream>
#include <type_traits>
// 编译时递归计算阶乘
template<int N>
struct Factorial {
static constexpr int value = N * Factorial<N - 1>::value;
};
template<>
struct Factorial<0> {
static constexpr int value = 1;
};
// 编译时类型列表
template<typename... Types>
struct TypeList {};
template<typename List>
struct Length;
template<typename... Types>
struct Length<TypeList<Types...>> {
static constexpr size_t value = sizeof...(Types);
};
// 编译时条件选择
template<bool Condition, typename TrueType, typename FalseType>
struct Conditional {
using type = TrueType;
};
template<typename TrueType, typename FalseType>
struct Conditional<false, TrueType, FalseType> {
using type = FalseType;
};
// 类型萃取
template<typename T>
struct RemovePointer {
using type = T;
};
template<typename T>
struct RemovePointer<T*> {
using type = T;
};
template<typename T>
using RemovePointer_t = typename RemovePointer<T>::type;
// 编译时循环展开
template<size_t N>
struct Loop {
template<typename Func>
static void execute(Func&& func) {
func(N - 1);
Loop<N - 1>::execute(std::forward<Func>(func));
}
};
template<>
struct Loop<0> {
template<typename Func>
static void execute(Func&&) {}
};
int main() {
std::cout << "=== 模板元编程 ===" << std::endl;
// 编译时计算
constexpr int fact5 = Factorial<5>::value;
std::cout << "5! = " << fact5 << std::endl;
// 类型列表长度
using MyTypes = TypeList<int, double, std::string, char>;
constexpr size_t length = Length<MyTypes>::value;
std::cout << "类型列表长度: " << length << std::endl;
// 条件类型选择
using SelectedType = Conditional<true, int, double>::type;
static_assert(std::is_same_v<SelectedType, int>);
std::cout << "条件选择成功" << std::endl;
// 类型萃取
using IntType = RemovePointer_t<int*>;
static_assert(std::is_same_v<IntType, int>);
std::cout << "指针类型萃取成功" << std::endl;
// 编译时循环
std::cout << "编译时循环展开: ";
Loop<5>::execute([](size_t i) {
std::cout << i << " ";
});
std::cout << std::endl;
return 0;
}总结
C++模板是强大的泛型编程工具,支持编译时多态和元编程:
模板类型
- 函数模板: 泛型函数
- 类模板: 泛型类
- 变参模板: 可变参数
- 模板特化: 特定类型优化
高级技术
| 技术 | 用途 | 特点 |
|---|---|---|
| SFINAE | 条件编译 | 类型检测 |
| 元编程 | 编译时计算 | 零运行时开销 |
| 类型萃取 | 类型操作 | 编译时类型推导 |
| 概念 | 类型约束 | C++20特性 |
最佳实践
- 使用auto减少模板复杂度
- 合理使用模板特化
- 利用SFINAE进行类型检测
- 避免过度使用模板元编程
- 提供清晰的错误信息
模板让C++具有强大的泛型编程能力,是现代C++的核心特性。