写一个简单的累加模板,如下:
template<typename T>
T accum(T const* beg, T const* end)
{
T total{};
while(beg != end)
{
total += * beg;
++ beg;
}
return total;
}
int main()
{
int num[] = { 1, 2, 3, 4, 5 };
std::cout << "the average value of the integer values is "
<< accum(num, num + 5) / 5
<<std::endl;
char name[] = "templates";
int length = sizeof(name) - 1;// (try to) print average character value
std::cout << "the average value of the characters in \""
<< name << "\" is "
<< accum(name, name + length) / length << std::endl;
return 0;
}
运行结果
很明显 当T为char类型是结果错误。
打印累加过程看看:
发现问题出在:
char类型的取值范围是 -128 ~ +127,
std::cout<<int(char(127))<<" "<< int(char(128)) << " " << int(char(129)) << std::endl;
输出是: 127 -128 -127
所以累加函数,当T为char类型时,T total{};
代码的需要改成 int total{}
因为char类型的数据做累加的时候太容易超出取值范围,而产生数字溢出的错误了
那怎么对char类型的数据特殊处理呢?
类似函数重载的思路,这里叫做 模板特化
#pragma once
#include<iostream>
// 特化的例子
// 首先,要写出模板的一般形式(原型)
template<typename T>
auto accum(T const* beg, T const* end)
{
T total{};
while (beg != end)
{
total += *beg;
++beg;
}
return total;
}
// 其次,我们要指定T是char时候的代码,这就是特化:
template<>
auto accum<char>(char const* beg, char const* end)
{
int total{};
while (beg != end)
{
total += *beg;
++beg;
}
return total;
}
测试:
int main()
{
int num[] = { 1, 2, 3, 4, 5 };
std::cout << "the average value of the integer values is "
<< accum(num, num + 5) / 5
<<std::endl;
char name[] = "templates";
int length = sizeof(name) - 1;// (try to) print average character value
std::cout << "the average value of the characters in \""
<< name << "\" is "
<< accum(name, name + length) / length << std::endl;
float dnum[] = { 1.1, 2.1, 3.1, 4.1, 5.1 };
std::cout << "the average value of the integer values is "
<< accum(dnum, dnum + 5) / 5.0
<< std::endl;
return 0;
}
结果:
可以看出 只有char类型的数据,调用的特化的模板
int 和double类型都调用的一般模板
这里也可以用Traits解决这个问题
#pragma once
template<typename T>
struct AccumulationTraits;
template< >
struct AccumulationTraits<char>
{
using AccT = int;
};
template<>
struct AccumulationTraits<short>
{
using AccT = int;
};
template<>
struct AccumulationTraits<int>
{
using AccT = long;
};
template<>
struct AccumulationTraits<unsigned int>
{
using AccT = unsigned long;
};
template<>
struct AccumulationTraits<float>
{
using AccT = double;
};
template<typename T>
auto accum(T const* beg, T const* end)
{
// return type is traits of the element type
using AccT = typename AccumulationTraits<T>::AccT;
// assume this actually creates a zero value
AccT total{};
while (beg != end)
{
total += *beg;
++beg;
}
return total;
}
该问题的核心解决思路是:根据不同的T ,初始化不同类型的total。
这里首先给出 模板的一般形式(原型)
template<typename T>
struct AccumulationTraits;
依次给出不同类型需要的total类型
template< >
struct AccumulationTraits<char>
{
using AccT = int;
};
假设是char类型 那么AccT 就是 int
在auto accum(T const* beg, T const* end)
函数中:
使用
using AccT = typename AccumulationTraits<T>::AccT;
获取 想要的total类型,完成累加操作
参考文献
模板元编程基础
《C++ Templates》