value trait
在上节的代码中,构造函数AccT()不一定会返回一个符合条件的值,而且类型AccT也
不一定具有一个缺省的构造函数。我们可以再次使用trait来解决这个函数。
//accumtraits3.h
template<typename T>
class AccumulationTraits;
template<>
class AccumulationTraits<char>
{
public:
typedef int AccT;
static AccT const zero = 0;
};
template<>
class AccumulationTraits<short>
{
public:
typedef int AccT;
static AccT const zero = 0;
};
template<>
class AccumulationTraits<int>
{
public:
typedef long AccT;
static AccT const zero = 0;
};
template<>
class AccumulationTraits<float>
{
public:
typedef double AccT;
static AccT const zero = 0;//在类中只有整型和枚举类型的静态常量才能初始化
//static AccT const zero; //如果这样定义可以,然后在源文件进行初始化
//初始化语句为:
//double const AccumulationTraits<float>::zero = 0.0;
};
在上面的代码中,我们的新trait是一个常量,而常量是在编译期进行求值的,因此,
accum()现在修改如下:
//accum3.h
#ifndef ACCUM_H
#define ACCUM_H
#include "accumtraits3.h"
template<typename T>
inline
typename AccumulationTraits<T>::AccT accum(T const* beg,T const* end)
{
//返回类型是元素类型的trait
typedef typename AccumulationTraits<T>::AccT AccT;
AccT total = AccumulationTraits<T>::zero;
while (beg != end)
{
total += *beg;
++beg;
}
return total;
}
#endif
然而,这种解决方案的一个缺点是:在所在类的内部,C++只允许我们对整型和枚举类型初始化
成静态成员变量。显然,对于诸如浮点型的其他类型(也包括我们自己定义的类),我们就不能
使用上面的解决方案。譬如下面的特化就是错误的:
...
template<>
class AccumulationTraits<float>
{
public:
typedef double AccT;
static double const zero = 0.0;//错误:并不是一个整形变量
};
对于这个问题,一个直接的解决方法就是不在所在类的内部定义这个value trait,如下所示:
template<>
class AccumulationTraits<float>
{
public:
typedef double AccT;
static double const zero ;
};
然后在源文件中进行初始化:
...
double const AccumulationTraits<float>::zero = 0.0;
尽管可以正常运行,但是该解决方案有一个显著的缺点:这种解决方法对编译器而言是不可知的。
也就是说,在处理客户端文件的时候,编译器通常都不会知道位于其他文件的定义。于是,在上面
这个例子中,编译器根本就不能够知道zero的值是0这个事实。
因此,我们趋向于实现下面这种value trait,而且不需要保证内联成员函数返回的必须是整型值。
我们重写改写我们的程序:
//accumtraits4.h
template<typename T>
class AccumulationTraits;
template<>
class AccumulationTraits<char>
{
public:
typedef int AccT;
static AccT zero()
{
return 0;
}
};
template<>
class AccumulationTraits<short>
{
public:
typedef int AccT;
static AccT zero()
{
return 0;
}
};
template<>
class AccumulationTraits<int>
{
public:
typedef long AccT;
static AccT zero()
{
return 0;
}
};
template<>
class AccumulationTraits<unsigned int>
{
public:
typedef unsigned long AccT;
static AccT zero()
{
return 0;
}
};
template<>
class AccumulationTraits<float>
{
public:
typedef double AccT;
static AccT zero()
{
return 0;
}
};
对于应用程序而言,唯一的区别就是在使用的时候使用了函数调用语法
AccT total = AccumulationTraits<T>::zero();

浙公网安备 33010602011771号