浅谈萃取技术

在STL中,以泛型技术为中心的设计贯穿着整个设计,模板类的运用,使得代码的复用率大大提高。萃取技术是在模板的基础上,采用相同的方式,却可以将不同的东西提取出来。

为什么要有萃取技术?
模板实现了程序的泛型化,但当有非模板类型传递时,我们就不能只套用模板,还需要对模板的参数进行加设。

template<class T1, class T2>
class MyClass
{
public:
    MyClass()
    {
        cout<<"MyClass<T1, T2>"<<endl;
    }
};
template<class T>
class MyClass<T,T>
{
public:
    MyClass()
    {
        cout<<"MyClass<T,T>"<<endl;
    }
};
template<class T>
class MyClass<T*,T*>
{
public:
    MyClass()
    {
        cout<<"MyClass<T*,T*>"<<endl;
    }
};
int main()
{
    MyClass<int,int> mc;
    MyClass<int,double> mc1;
    MyClass<int*,int*>mc2;
    return 0;
}

代码中不同的参数调用不同的模板,编译器根据参数列表进行最优匹配。通过模板参数的推导机制,我们实现了指针所指不同的参数的类型。
但是,我们如果需要不同的返回值时,问题就出现了,同参不同返回值的模板在程序中是不能编译通过的(类似函数的重载,不同返回值的相同函数会导致二义性)。
解决这个问题可以对指向对象类型的制定一个别名。

template <class T>
class A
{
    typedef T value_type;
    T *ptr;
    A(T *p = 0):ptr(p){}
    T& operator*()const
    {return *ptr;}
};
template <class I>
{
    typename I::value_type func(iter)
    {return *iter}
};

通过typedef我们返回了ptr和iter两种不同的指针,但这个方法是有很大缺陷的。我们返回的指针都是定义的,但对于原生指针如int *,func是不能接受的。

template partial specialization 偏特化
偏特化的设计思想是加一个中间层,将智能指针和原生指针统统封装起来。

class CIntArray
{
public:
    CIntArray()
    {
        for(int i=0; i<10; ++i)
        {
            a[i] = i+1;
        }
    }
    int GetSum(int n)
    {
        int sum = 0;
        for(int i=0;i<10; ++i)
        {
            sum += a[i];
        }
        return sum ;
    }
private:
    int a[10];
};

class CFloatArray
{
public:
    CFloatArray()
    {
        for(int i=0; i<10; ++i)
        {
            f[i] = i+1.11f;
        }
    }
    float GetSum(float n)
    {
        float sum = 0.0f;
        for(int i=0;i<10; ++i)
        {
            sum += f[i];
        }
        return sum ;
    }
private:
    float f[10];
};

template<class T>
class NumTraits
{};

template<>
class NumTraits<CIntArray>
{
public:
    typedef int result_type;
    typedef int input_type;
};
template<>
class NumTraits<CFloatArray>
{
public:
    typedef float result_type;
    typedef float input_type;
};

template<class T>
class CApply
{
public:
    typename NumTraits<T>::result_type GetSum(T &t,
                                        typename NumTraits<T>::input_type n )
    {
        cout<<typeid(typename NumTraits<T>::result_type).name()<<endl;
        return t.GetSum(n);
    }
};

我们将int 型和 float 型分别封装,注意:封装的名字一样哦
这样我们只需调用input_type和result_type.就可以萃取出不同类型int ,float的函数返回值了。
总结下,我们之所以要萃取迭代器相关的类型,无非是要把迭代器相关的类型用于声明局部变量,用作函数的返回值等行为。对于原声指针和其他类型的指针,采用了模板偏特化技术对其的特殊处理,从而达到萃取的目的。

你可能感兴趣的:(泛型)