[转]C++模板元编程——Traits
通过一个计算序列元素的累加和的小函数来说明traits的使用。
计算一个序列的累加和:
template<typename T>
T accum(const T* beg, const T* end)
{
T total = T();
while(beg != end)
{
total += *beg;
++beg;
}
return total;
}
使用accum:
int a[] = {3, 5, 7, 9};
const char* str = "abcd";
cout << "the a average: " << accum(a,a + 4) / 4 << endl;
cout << "the str average: " << accum(str,str + 4) / 4 << endl;
输出结果:
the a average: 6
the str average: -29
<style type="text/css"> .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }</style>
问题来了,"abcd" 串的平均值居然是-29, 这明显是不对的。问题出在T total,total 的类型为char,导致total += *beg 溢出。
解决的办法是通过类型T,得到一个比T能够表达更大范围的类型T1, 尽可能的保证不溢出。
1 特征类(traits)
定义AccumTraits特征类:
template<typename T>
struct AccumTraits
{
typedef T type; //默认情况下AccumTraits<T>::type 即为T
};
AccumTraits特征类char类型的特化:
template<>
struct AccumTraits<char>
{
typedef int type; // //AccumTraits<char>::type 即为int
};
AccumTraits特征类int类型的特化:
template<>
struct AccumTraits<int>
{
typedef long type;
};
应该特化各种常用的容易溢出的类型如:char、short、int、float,以及相应的unsigned char、unsigned short ...
重新实现accum模板函数:
<style type="text/css"> .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }</style>
template<typename T>
typename AccumTraits<T>::type
accum(const T* beg, const T* end)
{
typename AccumTraits<T>::type total = AccumTraits<T>::type();
while(beg != end)
{
total += *beg;
++beg;
}
return total;
}
再次使用该函数:
int a[] = {3, 5, 7, 9};
const char* str = "abcd";
cout << "the a average: " << accum(a,a + 4) / 4 << endl;
cout << "the str average: " << accum(str,str + 4) / 4 << endl;
输出结果:
the a average: 6
the str average: 98
<style type="text/css"> .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }</style>