一、模板参数类型
1.作用域问题
template<class Container>
void Print(const Container& v) {
// 必须使用typename明确告诉编译器这是类型
typename Container::const_iterator it = v.begin();
while (it != v.end()) {
cout << *it << " ";
++it;
}
}
- typename作用:当模板参数中存在嵌套类型时,必需使用typename明确标识。(原因:因为模板参数里的嵌套体类型未实例化,无法明确类型,加typename来明确类型。)
- 替代方案:使用auto自动推导(C++11起)
auto it = v.begin(); // 更简洁的写法
但是在有些场景下是不能用这种简洁的写法,比如在priority_queue的类模板中:
2.非类型模板参数
template<class T, size_t N>
class Stack {
private:
T _a[N]; // 非类型模板参数必须是常量整型
};
- 特点:
- 必须是常量
- 必须是整型(int,size_t等)
- 实例化后不可修改
3.按需实例化
Stack<int, 10> st1; // 模板类声明时不会实例化所有成员
st1.func(); // 只有调用时才会实例化对应成员
- 核心特点:模板类成员函数只有在被调用时才会实例化
二、array容器
array<int, 10> a;
a[10] = 1; // 严格越界检查(编译/运行时报错)
特性 | 普通数组 | array容器 |
越界读 | 不检查 | 严格检查 |
越界写 | 部分情况检查 | 严格检查 |
迭代器支持 | 无 | 支持 |
作为参数传递 | 退化指针 | 保留大小信息 |
三、模板特化
1.函数模板特化
- 特点:必须显示指定模板参数类型
template<>
bool Less<int*>(int* left, int* right) {
return *left < *right;
}
2.类模板特化
- 特化类型:
- 全特化:完全指定所有模板参数
- 偏特化:
- 部分参数特化
- 对参数类型添加限制(指针、引用等)
// 原模板
template<class T1, class T2>
class Data { /*...*/ };
// 全特化
template<>
class Data<int, double> { /*...*/ };
// 偏特化(部分参数)
template<class T1>
class Data<T1, double> { /*...*/ };
// 偏特化(类型限制)
template<class T1, class T2>
class Data<T1*, T2*> { /*...*/ };
四、模板分离编译
1.典型问题
// Stack.h
template<class T, class Container>
void Stack<T, Container>::push(const T& x) { /*...*/ }
- 链接错误原因:模板成员函数未被实例化,导致符号表找不到对应实现。
2.解决方案
方案一:显示实例化
template class Stack<int, vector<int>>; // 在.cpp文件中显式实例化
方案二:声明定义统一存放
template class Stack<int, vector<int>>; // 在.cpp文件中显式实例化