C深入理解C模板从原理到实践
目录
【C++】深入理解C++模板:从原理到实践
引言
C++模板是泛型编程的核心工具,它允许开发者编写与类型无关的代码。然而,模板的实现机制和编译过程往往令人感到神秘。本文将通过模板 实例化过程 、 类型推导规则 和 模板元编程 三个维度,深入理解C++模板的工作原理。
1、模板基础知识
1.1 函数模板
template <class T>
void Swap(T& a, T& b) {
T temp = a;
a = b;
b = temp;
}
- 编译器通过调用上下文推导
T
的类型。 - 生产具体类型版本的过程成为 隐式实例化 。
template <class T>
void Swap(T& a, T& b) {
T temp = a;
a = b;
b = temp;
}
int main() {
int a = 1, b = 2;
std::cout << a << " " << b << std::endl;
Swap(a, b);
std::cout << a << " " << b << std::endl;
std::cout << "---------" << std::endl;
double c = 1.2, d = 3.4;
std::cout << c << " " << d << std::endl;
Swap(c, d);
std::cout << c << " " << d << std::endl;
return 0;
}
1.2 类模板
template <class T>
class Vector {
public:
Vector(int n = 5)
: size_(0), capacity_(n)
{
data_ = new T[n];
}
void PushBack(const T& item) {
// 尾插逻辑...
}
~Vector() {
delete[] data_;
size_ = capacity_ = 0;
}
private:
T* data_;
int size_;
int capacity_;
};
- 必须显式指定模板参数类型(C++17前)。
- 支持成员函数模板和静态成员。
template <typename T>
class Vector {
public:
Vector(int n = 5)
: size_(0), capacity_(n)
{
data_ = new T[n];
}
void PushBack(const T& item) {
// 尾插逻辑...
}
~Vector() {
delete[] data_;
size_ = capacity_ = 0;
}
private:
T* data_;
int size_;
int capacity_;
};
int main() {
Vector<int> v;
return 0;
}
typename
是用来定义模板参数的关键字,也可以使用class
。
2、模板实例化机制
2.1 两阶段编译
- 模板定义阶段:检查语法和与模板参数无关的错误。
- 实例化阶段:生产具体类型的代码,检查类型相关操作。
2.2 实例化控制
- 显示实例化(减少代码膨胀)。
template <class T>
void Swap(T& a, T& b) {
T temp = a;
a = b;
b = temp;
}
template <class T>
class Vector {
public:
Vector(int n = 5)
: size_(0), capacity_(n)
{
data_ = new T[n];
}
void PushBack(const T& item) {
// 尾插逻辑...
}
~Vector() {
delete[] data_;
size_ = capacity_ = 0;
}
private:
T* data_;
int size_;
int capacity_;
};
template class Vector<int>; // 显示实例化整个类
template void Swap<int>(int&, int&); // 显示实例化函数
- 外部实例化声明(C++11)。
extern template class Vector<int>;
3、模板参数推导
3.1 类型推导规则
- 函数模板参数推导遵循以下优先级:
完美匹配。
类型提升(
float
→ \rightarrow
→
double
)。标准转换(
int
→ \rightarrow
→
long
)。用户定义转换。
3.2 CTAD(类模板参数推导)
- C++17引入的自动推导机制。
std::vector v{1,2,3}; // 推导为std::vector<int>
4、模板特化与偏特化
4.1 全特化
template <>
class ClassName<void*> {
//针对void*类型的特殊实现
};
4.2 偏特化
template <class T>
class ClassName<T*> {
//针对所有指针类型的通用实现
};
5、模板元编程
5.1 编译时计算
template <int N>
struct Factorial {
static const int ret = N * Factorial<N - 1>::ret;
};
template <>
struct Factorial<0> {
static const int ret = 1;
};
int main() {
std::cout << Factorial<5>::ret << std::endl; // 120
return 0;
}
5.2 SFINAE与类型检查
template <class T>
class std::enable_if<std::is_integral<T>::value>::type process(T val) {
// 仅对整数类型生效的实现
}
5.3 C++20概念(Concepts)
template <class T>
requires std::floating_point<T>
T precise_calc(T a, T b) {
// 高精度浮点计算
}
6、模板实践建议
- 避免过度使用模板元编程(TMP)。
- 使用
static_assert
进行模板参数校验。 - 注意模板导致的代码膨胀问题。
- 有限选择标准库类型特征(type_traits)