特化反义就是泛化,泛化:模板,可以随便指定类型
特化:对特殊的类型(类模板参数)进行特殊的对待
一、类模板特化
1.1类模板全特化
a)常规全特化
必须先有泛化版本才能存在特化版本。只要涉及特化,一定先存在泛化。
特化版本代码编译器会优先选择。
#include <iostream>
#include <map>
using namespace std;
template<typename T, typename U>
struct TC//泛化的TC类模板
{
void functest()
{
cout << "泛化版本" << endl;
}
};
template<>//全特化:所以类型模板参数都用具体类型代表,所以这里的template后面<>为空
struct TC<int, int>//上面的T绑定到这里第一个int,U绑定第二个int
{
//对特化版本做单独处理
void functest()
{
cout << "int,int的特化版本" << endl;
}
};
template<>//全特化:所以类型模板参数都用具体类型代表,所以这里的template后面<>为空
struct TC<double, int>
{
//对特化版本做单独处理
void functest()
{
cout << "int,int的特化版本" << endl;
}
};
int main()
{
TC<char, int>tcchar;
tcchar.functest();//泛化版本
TC<int, int>tcint;
tcint.functest();//特化版本
return 0;
}
泛化版本
int,int的特化版本
b)特化成员函数而不是模板
看如下代码
#include <iostream>
using namespace std;
template<typename T, typename U>
struct TC//泛化的TC类模板
{
TC()
{
cout << "泛化版本构造函数" << endl;
}
void functest()
{
cout << "泛化版本" << endl;
}
};
template<>//全特化:所以类型模板参数都用具体类型代表,所以这里的template后面<>为空
struct TC<int, int>//上面的T绑定到这里第一个int,U绑定第二个int
{
TC()
{
cout << "int,int特化版本构造函数" << endl;
}
//对特化版本做单独处理
void functest()
{
cout << "int,int的特化版本" << endl;
}
};
template<>//全特化:所以类型模板参数都用具体类型代表,所以这里的template后面<>为空
void TC<double, int>::functest()
{
//对特化版本做单独处理
cout << "double,int的特化版本的成员函数" << endl;
};
int main()
{
TC<double, int>ditest;
ditest.functest();
return 0;
}
泛化版本构造函数
double,int的特化版本的成员函数
1.2类模板的偏特化(局部特化)
偏特化从两个方面说起:一个是从模板参数数量,一个是模板参数范围
模板参数数量偏特化
#include <iostream>
using namespace std;
template<typename T, typename U, typename W>
struct TC//泛化的TC类模板
{
void functest()
{
cout << "泛化版本" << endl;
}
};
//偏特化:从参数上进行偏特化,绑定2个类型模板,留一个类型模板参数
template<typename U>//因为另外两个被我绑定到具体类型,所以这里留一个U类型模板参数
struct TC<int, U, int>
{
//对特化版本做单独处理
void functest()
{
cout << "偏特化int,int版本" << endl;
}
};
int main()
{
TC<double, double, double>itest;
itest.functest();
TC<int, double, int>iditest;
iditest.functest();
return 0;
}
泛化版本
偏特化int,int版本
模板参数范围特化
模板参数范围特化:int, const int(比int小)
原来T,现在T*(从任意类型T缩小为指针类型T*)
原来是T,现在T&左值引用,或者现在是T&&(右值引用),都叫范围缩小
#include <iostream>
using namespace std;
template<typename T>
struct TC//泛化的TC类模板
{
void functest()
{
cout << "泛化版本" << endl;
}
};
//偏特化:模板参数范围上的特化版本
template<typename T>
struct TC<const T>//const的特化版本
{
//对特化版本做单独处理
void functest()
{
cout << "偏特化const版本" << endl;
}
};
template <typename T>
struct TC<T *>//T* 的特化版本
{
void functest()
{
cout << "const T*特化版本" << endl;
}
};
template <typename T>
struct TC<T &>//T* 的特化版本
{
void functest()
{
cout << "T &左值引用特化版本" << endl;
}
};
template <typename T>
struct TC<T &&>//T* 的特化版本
{
void functest()
{
cout << "T &&右值引用特化版本" << endl;
}
};
int main()
{
TC<double> td;
td.functest();
TC<const double> td2;
td2.functest();
TC<double *> tpd;
tpd.functest();
TC<const double *> tpd2;
tpd2.functest();
TC<int &>tcyi;
tcyi.functest();
TC<int &&>tcyi2;
tcyi2.functest();
return 0;
}
泛化版本
偏特化const版本
const T*特化版本
const T*特化版本
T &左值引用特化版本
T &&右值引用特化版本
全特化:特化完了就是一个具体的类了。
局部特化:特化完后它本质上还是个模板。
函数模板特化
函数模板只能全特化,不能偏特化
#include <iostream>
using namespace std;
template<typename T,typename U>
void functest(T &tmprv, U&tmprv2)
{
cout << "泛化版本" << endl;
cout << tmprv << endl;
cout << tmprv2 << endl;
}
template<>
void functest(int &tmprv, int &tmprv2)
{
cout << "---------begin--------" << endl;
cout << "functest特化版本int,int" << endl;
cout << tmprv << endl;
cout << tmprv2 << endl;
cout << "----------end---------" << endl;
}
int main()
{
const char *p = "I Love China!";
int i = 12;
functest(p, i);
int j = 13;
functest(i, j);
return 0;
}
泛化版本
I Love China!
12
---------begin--------
functest特化版本int,int
12
13
----------end---------
全特化函数模板实际上等价于实例化 一个函数模板,并不是等价于一个函数重载
void functest<int ,int>(int &, int &){};//全特化,等价于实例化一个函数模板
void functest(int &tmprv, int &tmprv2);//重载长这样
但是在调用时候都是functest(i, j)那么编译器会执行那个函数呢,在以上代码中加入重载函数,其它不变
void functest(int &tmprv, int &tmprv2)
{
cout << "functest重载函数" << endl;
}
int main()
{
const char *p = "I Love China!";
int i = 12;
functest(p, i);
int j = 13;
functest(i, j);
return 0;
}
泛化版本
I Love China!
12
functest重载函数
结果发现优先调用重载函数,编译器选择->普通->特化->泛化
关于模板特化版本 放置位置建议:
- 模板定义、实现都放在一个.h文件中
- 模板的特化版本和模板的泛化版本都应该放在同一个.h中
- .h文件前面放泛化,后边放特化