fixed trait
要求:编写一个能适合许多类型的模板来完成一个累加操作
解答1:
//定义一个模板函数 #ifndef ACCUM_H #define ACCUM_H template<typename T> inline T accum(T const* beg,T const* end) { T total=T();//假设T()事实上会产生一个等于0的值 while(beg != end) { total += *beg; ++beg; } return total; } #endif
解析:上面的代码,有两个问题:
(1)如何正确生成一个0值,以便开展我们的求和过程。
(2)如何确保T类型相加的和不会溢出。
比如:
我们在下面的源文件中调用上述代码:
#include"accum0.h" #include<iostream> int main() { int num[] = {1,2,3,4,5}; char name[] = "templates"; int length = sizeof(name)-1; std::cout << "The average value of the integer values is :" << accum(&num[0],&num[5])/5 << std::endl; std::cout << "The average value of the characters in \" " << name << "\" is: " << accum(&name[0],&name[length])/length << std::endl; return 0; }
代码产生的结果为:
The average value of the integer values is :3
The average value of the characters in “templates” is :-5
我们发现当我们使用字符char类型的时候,就发生了求和溢出的现象。
显然,我们可以通过引入一个额外的模板参数AccT来解决这个问题,其中
AccT描述了变量total的类型,然而这样会给该模板的使用者都强加了一个
额外的负担,他们每次在调用这个模板的时候,都要指定这个额外的类型,
我们每次不得不这样来写:
accum<int>(&nume[0],&name[length])
虽说这个约束不是很麻烦,但是我们仍然希望避免这个约束。
此时,我们引入trait模板,其中定义的是和类型T的一些关联特征。
//accumtraits2.h template<typename T> class AccumulationTraits; template<> class AccumulationTraits<char>{ public: typedef int AccT; }; template<> class AccumulationTraits<short>{ public: typedef int AccT; }; template<> class AccumulationTraits<int>{ public: typedef long AccT; }; template<> class AccumulationTraits<unsigned int>{ public: typedef unsigned long AccT; }; template<> class AccumulationTraits<float>{ public: typedef double AccT; };
在上面的代码中,模板AccumulationTraits被称为一个trait模板,因为
它含有它的参数类型的一个trait。
现在,我们可以改写前面写的accum()模板了:
//accum2.h #ifndef ACCUM_H #define ACCUM_H #include "accumtraits2.h" template<typename T> inline typename AccumulationTraits<T>::AccT accum(T const* beg,T const* end) { typedef AccumulationTraits<T>::AccT AccT; AccT total = AccT(); while(beg != end) { total += *beg; ++beg; } return total; } #endif
现在我们运行前面的程序,就会出现我们期望的结果:
The average value of the integer values is :3
The average value of the characters in “templates” is :108