C++范型三:数据类型表
类的数据类型成员
C++中,在类模板中用typedef
定义的数据类型称为内嵌类型nested type
template<typename T>
class MyTraits{
public:
typedef T mytype;
};
如下,使用内嵌类型在类外定义变量
typename MyTraits<int>::mytype n;
可知,类外引用类模板的公有类型成员和引用类静态成员的写法相同,为了区分,在引用类型成员时需用关键字typename
表明
typedef
为现有类型定义别名,增加程序可读性,还简化复杂的类型名
如类型void (*b[10])(void(*)())
,变量名为b
先替换右边部分括号
typedef void(*pFunParam)()
再替换左边的变量b
typedef void(*pFunx)(pFunParam)
原声明可简化为
pFunx b[10]
typedef
最大的用处是编写平台无关代码,如typedef unsigned int uint32
,跨平台时,只需要维护typedef
即可
内嵌数据类型表和数据类型衍生
为了方便,将typedef
定义的所有公有数据类型及其衍生类型定义在一个类模板中形成一个数据类型表
typedef T value_type;
typedef T& reference;
typedef T* pointer;
数据类型表
若一个类模板中,全部成员都是公有数据类型,那这个类模板称为独立数据类型表,简称数据类型表,数据类型表可以规范代码的模板类型,是STL库用以规范代码的主要手段
如下数据类型表
template<typename T>
class TypeTb{
public:
typedef T value_type;
typedef T* pointer_type;
typedef T& reference_type;
};
定义一个类模板,继承自数据类型表
template<typename T>
class Num::public TypeTb<T>{
// todo:
};
使用继承自数据类型表的类模板
void func(
Num<int>::value_type x,
Num<int>::reference_type y,
Num<int>::pointer_type z){
cout<< "x="<< x<<endl;
cout<< "y=x="<< y<<endl;
cout<< *z<<endl;
}
此时会发现一个问题,函数func
的形参类型是固定的,如何将该函数用模板定义
// 错误实现
template<typename T>
void func(T<int>::value_type x, T<int>::reference_type y, T<int>::pointer_type z){
cout<< "x="<< x<<endl;
cout<< "y=x="<< y<<endl;
cout<< *z<<endl;
}
该函数模板中,类型占位符T
占的位置是Num
,而Num
不是类型,可知,类型占位符不是字符串上的简单替换
// 正确实现
template<typename T>
void func(
typename T::value_type x,
typename T::reference_type y,
typename T::pointer_type z){
cout<< "x="<< x<<endl;
cout<< "y=x="<< y<<endl;
cout<< *z<<endl;
}
/*
使用方式为:
typename Num<int>::value_type a= 100;
func<Num<int>>(a, a, &a);
*/
可以看出,类型占位符代表的真正类型是Num<int>
特化数据类型表
为了满足对于不同类型,有相同定义的场景,如:
class T1{
public:
int compute(char x, double y){ return x; }
};
class T2{
public:
double compute(double x, int y){ return x; }
};
定义一个特化数据类型表
class type1;
class type2;
template<typename T>
class TypeTb{};
template<>
class TypeTb<type1>{
public:
typedef int ret_type;
typedef char para1_type;
typedef double para2_type;
};
template<>
class TypeTb<type2>{
public:
typedef double ret_type;
typedef double para1_type;
typedef int para2_type;
};
为了将上述有类似定义的函数,使用不提供多个模板参数的模板实现,可结合特化数据类型表,实现如下:
template<typename T>
class Test{
public:
typename TypeTb<T>::ret_type compute(
typename TypeTb<T>::para1_type x, typename TypeTb<T>::para2_type y){
return x;
}
};
/*
test:
Test<type1> t1;
// t1.compute();
Test<type2> t2;
// t2.compute();
*/
STL中的Traits表
Traits实质上是特化数据类型表在STL中的一个具体应用,也是数据类型表,因其构思巧妙,而被称为Traits技巧
STL中用来指示数据位置的迭代器对象,大多数是包含内嵌数据类型表的类模板,从而能向外提供类型
C++指针也是用来指示数据位置的,理论上也属于迭代器范畴,为了接口的统一,指针也应该向外提供数据类型
使用特化模板实现指针的数据类型表
// 指针的特化模板
template<typename T>
struct Traits<T*>{ // 此时的 T 不是指针类型
typedef T value_type;
typedef value_type* pointer;
typedef value_type& reference;
};
/*
test:
Traits<double*>::value_type t=2;
*/
使用特化数据类型表解决了原生类型的数据类型表问题,但是各个迭代器的数据类型表分散于各个迭代器类中,在管理上造成麻烦,此时可用一个迭代器类型表的总表解决该问题,即Traits表
template<typename T>
struct Iterator1{
typedef T value_type;
typedef value_type* pointer;
typedef value_type& reference;
...
};
template<typename T>
struct Iterator2{
typedef T value_type;
typedef value_type* pointer;
typedef value_type& reference;
...
};
// 类型总表
template<typename T>
struct Traits{
typedef typename T::value_type value_type;
typedef typename T::pointer pointer;
typedef typename T::reference reference;
};
template<typename T>
struct Traits<T*>{
typedef T value_type;
typedef value_type* pointer;
typedef value_type& reference;
};
/*
test:
Traits<Iterator_1<int>>::value_type t=2;
Traits<Iterator_2<double>>::value_type t=2;
Traits<double*>::value_type t=2;
*/