下面是一个标准的类模板,他没有使用任何的模板特化技术
故无论模板参数 T 是什么类型,Stack 都具有相同的行为
template <typename T>
class Stack {
private:
std::vector<T> elems;
...
}
类模板特化有两种形式:
定义:指为所有模板参数都确定的情况下,为某个特定类型提供一个单独的实现
下方代码表示当模板参数为特定的 std::string
时,使用序号 2 后面的所有代码来对该类进行实例化
全特化要求
template<> ①
class Stack<std::string> { ②
private:
std::deque<std::string> elems; ③
public:
void push(std::string const & elem) {
elems.push_back(elem);
}
void pop(){
if (elems.empty()) return;
elems.pop_back();
}
std::string top() const{
if (elems.empty()) return NULL;
return elems.back();
}
}
定义:为一部分模板参数确定的情况下,为某个特定类型提供一个单独的实现
下方代码表示当我们传入的模板参数 T
都具有 T*
特征时,使用以下代码执行类实例化
template <typename T> ①
class Stack<T*> { ②
private:
std::list<T*> list; ③
public:
void push(T* & elem) {
list.push_front(elem);
}
void pop(){
if (list.empty()) return;
list.pop_front();
}
T* top() const{
if (list.empty()) return NULL;
return list.front();
}
}
假设当前有一个主类模板
template <typename T1, typename T2>
class MyClass {
…
};
那么对应的特化类模板可以这么写
表示接收到的第二个模板参数 T2 需为 int 类型的
template <typename T>
class MyClass<T,int> {
…
};
比如还有部分特化,可以参考以下代码
template <typename T1, typename T2>
class MyClass<T1*,T2*> {
…
};
定义:Traits 技术是一种编程技术,它在面向对象编程中用于实现代码重用和可组合性。Traits 技术可以让程序员定义一些可复用的组件,这些组件可以被多个类或对象使用,并且可以在运行时进行组合
下面介绍使用 traits
技术的一个简单案例
// 声明一个模板类 fp_traits,用于实现浮点类型的特性
template <typename numT>
struct fp_traits { };
// 模板特化,指定 float 类型的 fp_traits
template<>
struct fp_traits<float> {
typedef float fp_type; // 定义 typedef 为 float 类型
enum { max_exponent = FLT_MAX_EXP }; // 定义枚举常量,表示 float 类型的最大指数
static inline fp_type epsilon() // 定义 inline 函数,返回 float 类型的极小值
{ return FLT_EPSILON; }
};
// 模板特化,指定 double 类型的 fp_traits
template<>
struct fp_traits<double> {
typedef double fp_type; // 定义 typedef 为 double 类型
enum { max_exponent = DBL_MAX_EXP }; // 定义枚举常量,表示 double 类型的最大指数
static inline fp_type epsilon() // 定义 inline 函数,返回 double 类型的极小值
{ return DBL_EPSILON; }
};
// 声明模板类 matrix,使用 numT 模板参数表示矩阵中的数值类型
template <typename numT>
class matrix {
public:
typedef numT num_type; // 定义 typedef 为 numT 类型
typedef fp_traits<num_type> num_type_info; // 定义 typedef 为 fp_traits 类型
// 定义 inline 函数,返回 num_type_info 中的 epsilon() 函数结果
inline num_type epsilon()
{return num_type_info::epsilon();}
......
};
int main()
{
matrix <float> fm; // 定义一个 float 类型的矩阵对象
matrix <double> dm; // 定义一个 double 类型的矩阵对象
cout << "float matrix: " << fm.epsilon() << endl; // 输出 float 类型矩阵对象的 epsilon() 函数结果
cout << "double matrix: " << dm.epsilon() << endl; // 输出 double 类型矩阵对象的 epsilon() 函数结果
}
定义:由于 cpp 自带的类型处理方法很少,所以使用类模板特化技术,设计专门的类模板来提供所需信息的方法称为类型分类技术
// 类型模板,用于为指定类型 T 提供类型信息
template<typename T>
class TypeInfo {
public:
enum { IsPtrT = 0, IsRefT = 0, IsArrayT = 0 }; // 定义三个枚举常量,表示 T 不是指针、不是引用、不是数组
typedef T baseT; // 定义 typedef 为 T 类型
typedef T bottomT; // 定义 typedef 为 T 类型
};
// 类型模板特化,用于为指针类型 T* 提供类型信息
template<typename T>
class TypeInfo<T*> {
public:
enum { IsPtrT = 1, IsRefT = 0, IsArrayT = 0 }; // 定义三个枚举常量,表示 T* 是指针、不是引用、不是数组
typedef T baseT; // 定义 typedef 为 T 类型
typedef typename TypeInfo<T>::bottomT bottomT; // 定义 typedef 为 TypeInfo::bottomT 类型
};
// 类型模板特化,用于为引用类型 T& 提供类型信息
template<typename T>
class TypeInfo<T&> {
public:
enum { IsPtrT = 0, IsRefT = 1, IsArrayT = 0 }; // 定义三个枚举常量,表示 T& 不是指针、是引用、不是数组
typedef T baseT; // 定义 typedef 为 T 类型
typedef typename TypeInfo<T>::bottomT bottomT; // 定义 typedef 为 TypeInfo::bottomT 类型
};
// 类型模板特化,用于为大小为 N 的数组类型 T[N] 提供类型信息
template<typename T, size_t N>
class TypeInfo <T[N]> {
public:
enum { IsPtrT = 0, IsRefT = 0, IsArrayT = 1 }; // 定义三个枚举常量,表示 T[N] 不是指针、不是引用、是数组
typedef T baseT; // 定义 typedef 为 T 类型
typedef typename TypeInfo<T>::bottomT bottomT; // 定义 typedef 为 TypeInfo::bottomT 类型
};
定义:每当我们使用一个类型作为模板参数来实例化一个类模板或者函数模板时,C++编译器将生成一个和该类型对应的类或者函数,这会导致每次实例化都重复生成一次,造成代码膨胀
示例
// 定义一个 Vector 类型的对象 VPVector,元素类型为 void*,即指向任意类型的指针
Vector<void*> VPVector;
// 定义一个模板类 Vector,其中 T 为指针类型,继承自 VPVector
template<class T>
class Vector <T*>: public VPVector{
public:
// 重载 [] 运算符,返回类型为 T* 的指针
T*& operator[](int i) {
return (T*&)(VPVector::operator[](i));
};
};
int main()
{
// 定义一个 Vector 类型的对象 v1,用于存储 int 类型的指针
Vector<int*> v1;
// 定义一个 Vector 类型的对象 v2,用于存储 double 类型的指针
Vector<double*> v2;
// 定义一个 int 类型的变量 i 并初始化为 3,将 i 的地址赋给 v1 中第一个元素
int i = 3;
v1[0] = &i;
// 定义一个 double 类型的变量 d 并初始化为 3.14,将 d 的地址赋给 v2 中第一个元素
double d = 3.14;
v2[0] = &d;
}