1. 全局特化
1. 全类特化
- 哪种类型不好使,就对哪种类型做特化
- 对类模板做全类特化就相当于重新写了一个类,而且这个类是专门针对之前那个不好使的类型的
2. 成员特化
哪个成员函数不好使就对哪个成员函数做特化
#include <iostream>
#include <cstring>
using namespace std;
// 所以这个类中的add函数不适合 const char* 类型, 因为指针不能做加法
template<class T>
class CMath{
public:
CMath(T const& t1, T const t2):m_t1(t1), m_t2(t2){}
T add(void){
return m_t1 + m_t2;
}
private:
T m_t1;
T m_t2;
};
// 全类特化,相当于重新写一个针对特定类型(char* const)的类
/*
template<>
class CMath<char* const>{
public:
CMath(char* const& t1, char* const& t2):m_t1(t1), m_t2(t2){}
char* const add(void){
return strcat(m_t1, m_t2);
}
private:
char* const m_t1;
char* const m_t2;
};
*/
// 就比较麻烦,因为只有add函数不适合char* const类型, 只重写add函数就好
// 所有就有了成员特化
template<>
char* const CMath<char* const>::add(void){
return strcat(m_t1, m_t2);
}
int main(void){
CMath<int> m1(1, 1);
std::cout << m1.add() << std::endl; // 2
// 字符数组名是 char* const
char c_x[256] = "hello ", c_y[256] = "world!";
// 遇到 CMath<char* const>,就不会再去使用类模板实例化类,而是直接使用那个特化后的类
CMath<char* const>m2(c_x, c_y);
cout << m2.add() << endl; // hello world!
return 0;
}
2. 局部特化
函数模版不存在局部特化,只有类模版才能局部特化?
- 和全局特化的差别就是,看特化了几个类型参数,如果把所有的类型参数都特化成具体类型就是全局特化,如果只特化一部分类型参数就是局部特化。
#include <iostream>
using namespace std;
// 类模板
template <class T, class D>
class A{
public:
// 这里写static是为了可以直接通过类调用,不用实例化对象
static void foo(){
cout << "1. A<T, D>::foo()" << endl;
}
};
// 局部特化, 把D特化成short
template <class T>
class A<T, short>{
public:
static void foo(){
cout << "2. A<T, short>::foo()" << endl;
}
};
// 局部特化, 把D特化成T
template <class T>
class A<T, T>{
public:
static void foo(){
cout << "3. A<T, T>::foo()" << endl;
}
};
int main(void){
A<int, double>::foo(); // 1. A<T, D>::foo()
A<int , short>::foo(); // 2. A<T, short>::foo()
// A<short, short>::foo(); //编译报错,在2和3 之间产生歧义
return 0;
}
3. 类型形参缺省
#include <iostream>
#include <typeinfo>
using namespace std;
// 类模板
template <class T = short, class D = double>
class A{
public:
void print(void){
cout << "m_t: " << typeid(m_t).name() << ","
<< "m_d: " << typeid(m_d).name() << endl;
}
private:
T m_t;
D m_d;
};
int main(void){
A<int, float> m1;
m1.print(); // m_t: i,m_d: f
A<>m2;
m2.print(); // m_t: s,m_d: d
}
4. 数值形的模板参数
- 类型参数表中可以出现,数值型参数,还可以带缺省值
- 不能出现字符串,double这种类型,只能出现数值型参数,只能出现 int类型?
- size_t 是 long unsigned int
#include <iostream>
using namespace std;
// 类型参数表中可以出现,数值型参数,还可以带缺省值
template<class T, size_t S> // size_t S = 10
class Array{
public:
// 操作符重载
T& operator[](size_t i){
return m_arr[i];
}
size_t size(){
return S;
}
private:
T m_arr[S];
};
int main(void){
// Array<int> a; a 可以看做一个一维数组类,数组中每一个元素就是int类型
// m 可以看做一个一维数组,数组中每一个元素都是 Array<int> 类型,一个一维数组
// 所以m是一个二维数组
Array<Array<int,4>, 4 > m; // 后面两个< 分开写,避免和<< 歧义
for (int i=0; i<m.size(); i++){
for (int j=0; j<m.size(); j++){
m[i][j] = 1;
}
}
for (int i=0; i<m.size(); i++){
for (int j=0; j<m.size(); j++){
cout << m[i][j] << " ";
}
cout << endl;
}
return 0;
}
$ ./a.out
1 1 1 1
1 1 1 1
1 1 1 1
1 1 1 1
5. 模板技巧
个人感觉后面这两个都不常见,不过既然看到了,就大概写一下,留一个种子,万一以后开发中碰到了,也便于扩展。
5.1 模板型成员变量
- m_s 首先是一个成员变量,然后是由类模板 Arrary 实例化出的未知类,因为D是未知的
#include <iostream>
using namespace std;
template<class T>
class Array{
public:
// 操作符重载
T& operator[](size_t i){
return m_arr[i];
}
private:
T m_arr[10];
};
template <class D> class Sum{
public:
Sum(Array<D>& s):m_s(s){}
D add(){ //求和
D d = 0;
for(int i = 0; i < 10; i++){
d += m_s[i];
}
return d;
}
private:
Array<D> m_s; // 模板型成员变量
};
int main(void){
Array<int> a;
for (int i = 0; i < 10; i++){
a[i] = i + 1;
}
// Sum 类模板实例化的类 Sum<int> 来实例化一个对象s,并用a来赋初始值
Sum<int> s(a);
cout << s.add() << endl; //55
return 0;
}
5.2 模板型成员函数
类模板的成员函数模板
- foo是一个函数模板,又是一个成员函数, 可以直接叫 成员&函数模板
- 说白了就是类模板里嵌套一个成员函数模板。那么用的时候就需要先实例化类,再实例化函数
#include <iostream>
using namespace std;
template <class T>
class A{
public:
// 声明定义写一起
template<class D> void foo(){ //成员函数模板
cout << "A<T>::foo()" << endl;
}
// 声明定义分开写
template<class X> void foo2();
};
// 既然是模板嵌套,那就有两个帽子。还要有作用域限定
template<class T>
template<class X>
void A<T>::foo2(){
cout << "A<T>::foo2()" << endl;
}
int main(void){
// 1. 实例化类
A<int> m;
// 2. 实例化类
m.foo<double>(); // A<T>::foo()
m.foo2<double>(); // A<T>::foo2()
return 0;
}
5.3 模板型成员类型
#include <iostream>
using namespace std;
// 类模板嵌套类模板
template <class X>class A{
public:
template <class Y>class B{
public:
template <class Z>class C;
};
};
// 类模板C在外部实现
template <class X>
template <class Y>
template <class Z> class A<X>::B<Y>::C{ // 翻过两次作用域
public:
// 这里再来个成员函数模板, 用时需要实例化
template<class T>void foo(){
cout << "zhen e xin" << endl;
}
};
int main(void){
A<int>::B<int>::C<int> a;
a.foo<int>(); // "zhen e xin"
return 0;
}
5.4 模板型模板参数
- <> 里的模板形参可以是 类型,数值,类模板
- 上图中Arrary是一个类模板,它的模板参数是T
- Sum也是一个类模板,它的模板参数是C,类型是一个类模板:template <class D> class ,缺省值是 类模板Arrary。这就是模板型模板参数
#include <iostream>
using namespace std;
template<class T>
class Array{
public:
// 操作符重载
T& operator[](size_t i){
return m_arr[i];
}
private:
T m_arr[10];
};
template <class D, template<class M> class C> class Sum{
public:
// Sum(Array<D>& s):m_s(s){}
Sum(C<D>& s):m_s(s){}
D add(){ //求和
D d = 0;
for(int i = 0; i < 10; i++){
d += m_s[i];
}
return d;
}
private:
// Array<D> m_s;
C<D> m_s; // 模板型成员变量
};
int main(void){
Array<int> a;
for (int i = 0; i < 10; i++){
a[i] = i + 1;
}
// Sum 类模板实例化的类 Sum<int> 来实例化一个对象s,并用a来赋初始值
Sum<int, Array> s(a);
cout << s.add() << endl; //55
return 0;
}