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();

posted @ 2011-11-02 22:48  MagiCube  阅读(295)  评论(0编辑  收藏  举报