C++ traits技术
1、技术的发明是为了某个问题,traits也是一样。考虑下面的需求。
2、对两个变量相加,为了通用,使用模板方法,实现编译时多态。如下:
template <typename T>
T Add(T a,T b)
{
//...
}
3、对于int,double实现是一样的,直接相加就行了。但是对于char*,我们期望内容相加,返回一个新的指针。传统的解决办法使用方法过载,如下:
int Add(int a, int b);
double Add(double a, double b);
char* Add(char* a, char* b);
4、对于方法模板,存在问题,方法模板就是为了生成方法的,这里的T 可以是int,double,char*,根据模板实参具现化。这里要解决一个问题,方法模板根据不同的类型,生成不同的方法,也就是说过载方法模板,需要有一个形参表示类型的特性,比如int,char*,根据这个特性生成相应的方法,如下:
struct BaseType{};
struct CharPoint{};
// 对于基本类型,生成相应的方法
template <typename T>
T Do_Add(T a,T b,BaseType)
{
T c = a+b;
return c;
}
// 对于char指针,生成相应的方法
template <typename T>
T Do_Add(T a,T b,CharPoint)
{
// 这里存在安全隐患,要求调用者释放内存
T c = new char[strlen(a)+strlen(b)+1];
memset(c,0,strlen(a)+strlen(b)+1);
memcpy(c,a,strlen(a));
memcpy(c+strlen(a),b,strlen(b));
return c;
}
这里的BaseType和CharPoint是无名形参,因为并不使用这个形参,他们的目的只是为了让编译器生成不同的方法。
5、这里要解决一个问题,对于int和double,提取出BaseType,对于char*,提取出 CharPoint。怎么解决这个问题?
使用一个模板类,专门提取特性,默认提取出 BaseType,对于特殊的char* 使用偏特化提取出 CharPoint。所谓偏特化,就是缩小模板形参的范围,设计出一个特化的版本。也算就是说,对于大范围,默认有一个处理方式,在大范围中划出一个小范围,进行特殊处理。
如下:
template <typename T>
struct MyTraits
{
typedef BaseType value_type;
};
template <>
struct MyTraits<char*>
{
typedef CharPoint value_type;
};
6、接下来就看方法模板的实现,先使用traits 提取出特性,在调用方法,根据这个特性,生成不同的方法。如下:
template <typename T>
T Add(T a,T b)
{
typename MyTraits<T>::value_type type;
return Do_Add(a,b,type);
}
7、测试如下:
int main(int argc, char* argv[])
{
int a = 4;
int b = 7;
int c = Add(a,b);
char* pa = "abc";
char* pb = "123";
char* pc = Add(pa,pb);
return 0;
}