zoukankan      html  css  js  c++  java
  • C++笔记(8) template partitial specialization模板偏特化

    By SmartPtr(http://www.cppblog.com/SmartPtr/)

     

      说起C++的模板及模板特化, 相信很多人都很熟悉 ,但是说到模板特化的几种类型,相信了解的人就不是很多。我这里归纳了针对一个模板参数的类模板特化的几种类型, 一是特化为绝对类型; 二是特化为引用,指针类型;三是特化为另外一个类模板。
     这里用一个简单的例子来说明这三种情况:

    // general version
    template<class T>
    class Compare
    {
    public:
        
    static bool IsEqual(const T& lh, const T& rh)
        {
            
    return lh == rh;
        }
    };

    这是一个用于比较的类模板,里面可以有多种用于比较的函数, 以IsEqual为例。
     
    一、特化为绝对类型
    也就是说直接为某个特定类型做特化,这是我们最常见的一种特化方式, 如特化为float, double等

    // specialize for float
    template<>
    class Compare<float>
    {
    public:
        
    static bool IsEqual(const float& lh, const float& rh)
        {
            
    return abs(lh - rh) < 10e-3;
        }
    };

    // specialize for double
    template<>
    class Compare<double>
    {
    public:
        
    static bool IsEqual(const double& lh, const double& rh)
        {
            
    return abs(lh - rh) < 10e-6;
        }
    };


     
    二、特化为引用,指针类型
    这种特化我最初是在stl源码的的iterator_traits特化中发现的, 如下:

    template <class _Iterator>
    struct iterator_traits {
      typedef typename _Iterator::iterator_category iterator_category;
      typedef typename _Iterator::value_type        value_type;
      typedef typename _Iterator::difference_type   difference_type;
      typedef typename _Iterator::pointer           pointer;
      typedef typename _Iterator::reference         reference;
    };

    // specialize for _Tp*
    template <class _Tp>
    struct iterator_traits<_Tp*> {
      typedef random_access_iterator_tag iterator_category;
      typedef _Tp                         value_type;
      typedef ptrdiff_t                   difference_type;
      typedef _Tp
    *                        pointer;
      typedef _Tp
    &                        reference;
    };

    // specialize for const _Tp*
    template <class _Tp>
    struct iterator_traits<const _Tp*> {
      typedef random_access_iterator_tag iterator_category;
      typedef _Tp                         value_type;
      typedef ptrdiff_t                   difference_type;
      typedef 
    const _Tp*                  pointer;
      typedef 
    const _Tp&                  reference;
    };

     当然,除了T*, 我们也可以将T特化为 const T*, T&, const T&等,以下还是以T*为例:

    // specialize for T*
    template<class T>
    class Compare<T*>
    {
    public:
        
    static bool IsEqual(const T* lh, const T* rh)
        {
            
    return Compare<T>::IsEqual(*lh, *rh);
        }
    };

    这种特化其实是就不是一种绝对的特化, 它只是对类型做了某些限定,但仍然保留了其一定的模板性,这种特化给我们提供了极大的方便, 如这里, 我们就不需要对int*, float*, double*等等类型分别做特化了。

    三、特化为另外一个类模板

    这其实是第二种方式的扩展,其实也是对类型做了某种限定,而不是绝对化为某个具体类型,如下:

    // specialize for vector<T>
    template<class T>
    class Compare<vector<T> >
    {
    public:
        
    static bool IsEqual(const vector<T>& lh, const vector<T>& rh)
        {
            
    if(lh.size() != rh.size()) return false;
            
    else
            {
                
    for(int i = 0; i < lh.size(); ++i)
                {
                    
    if(lh[i] != rh[i]) return false;
                }
            }
            
    return true;
        }
    };


    这就把IsEqual的参数限定为一种vector类型, 但具体是vector<int>还是vector<float>, 我们可以不关心, 因为对于这两种类型,我们的处理方式是一样的,我们可以把这种方式称为“半特化”。

    当然, 我们可以将其“半特化”为任何我们自定义的模板类类型:

    // specialize for any template class type
    template <class T1> 
    struct SpecializedType
    {
        T1 x1;
        T1 x2;
    };
    template 
    <class T>
    class Compare<SpecializedType<T> >
    {
    public:
        
    static bool IsEqual(const SpecializedType<T>& lh, const SpecializedType<T>& rh)
        {
            
    return Compare<T>::IsEqual(lh.x1 + lh.x2, rh.x1 + rh.x2);
        }
    };


     这就是三种类型的模板特化, 我们可以这么使用这个Compare类:

       // int
        int i1 = 10;
        
    int i2 = 10;
        
    bool r1 = Compare<int>::IsEqual(i1, i2);

        
    // float
        float f1 = 10;
        
    float f2 = 10;
        
    bool r2 = Compare<float>::IsEqual(f1, f2);

        
    // double
        double d1 = 10;
        
    double d2 = 10;
        
    bool r3 = Compare<double>::IsEqual(d1, d2);

        
    // pointer
        int* p1 = &i1;
        
    int* p2 = &i2;
        
    bool r4 = Compare<int*>::IsEqual(p1, p2);

        
    // vector<T>
        vector<int> v1;
        v1.push_back(
    1);
        v1.push_back(
    2);

        vector
    <int> v2;
        v2.push_back(
    1);
        v2.push_back(
    2);
        
    bool r5 = Compare<vector<int> >::IsEqual(v1, v2);

        
    // custom template class 
        SpecializedType<float> s1 = {10.1f,10.2f};
        SpecializedType
    <float> s2 = {10.3f,10.0f};
        
    bool r6 = Compare<SpecializedType<float> >::IsEqual(s1, s2);


    注:感谢longshanks对于本文中"类模板"与"模板类"概念的澄清,已更正 (2007-7-16)
    posted on 2007-07-04 21:40 SmartPtr 阅读(3022) 评论(10)  编辑 收藏 引用

    FeedBack:
    # re: C++模板类的三种特化[未登录]
    2007-07-05 11:23 | yong
    第二和第三种实际上就是template的"偏特化"或叫"部分特化"。这个概念不是什么新鲜的东东~ 呵呵  回复  更多评论
      
    # re: C++模板类的三种特化
    2007-07-05 11:53 | SmartPtr
    从广义上来讲, 我觉得可以把这种情形归入模板偏特化。
    但是根据我们一般的理解,模板的偏特化是指需要根据模板的某些但不是全部的参数进行特化, 如下:
    template<class T1, class T2>
    class A
    {
    }

    template<class T1>
    class A<T1, int>
    {
    }

    说实话, 我第一次发现第二和第三种用法时, 还是觉得挺新鲜的,这到底是属于全特化还是偏特化, 我也说不清楚, 但这也不重要,只要我们知道有这种用法,能应用它就行了  回复  更多评论
      
    # re: C++模板类的三种特化
    2007-07-05 15:57 | walkspeed
    模板有两种特化,全特化和偏特化(局部特化)
    模板函数只能全特化,没有偏特化(以后可能有)。
    模板类是可以全特化和偏特化的。

    全特化,就是模板中模板参数全被指定为确定的类型。
    全特化也就是定义了一个全新的类型,全特化的类中的函数可以与模板类不一样。

    偏特化,就是模板中的模板参数没有被全部确定,需要编译器在编译时进行确定。

    在类型上加上const、&、*( cosnt int、int&、int*、等等)并没有产生新的类型。只是类型被修饰了。模板在编译时,可以得到这些修饰信息。

    以上的2、3就是偏特化。  回复  更多评论
      
    # re: C++模板类的三种特化
    2007-07-05 16:03 | walkspeed
    模 板的特化是非常有用的。它像一个在编译期的条件判断。当编译器在编译时找到了符合的特化实现,就会使用这个特化实现。这就叫编译器多态(或者叫静态多 态)。这种东西对编写基础库是很有用的。这也就是为何c++的基础库大量使用了模板技术,而且大量使用了特化,特别是偏特化。

    在泛型中,利用特化类得到类新的特性,以便找到最适合这种特性的实现。而这一切都是在编译时完成。  回复  更多评论
      
    # re: C++模板类的三种特化
    2007-07-05 17:30 | SmartPtr
    谢谢walkspeed的回复, 我想对于全特化和偏特化这么理解应该是正确的, 就是全特化后确定了一个真正的类型, 而偏特化后其实还是一个原类型, 这样的话, 以上2, 3的确属于偏特化。
    模板的运用的确很广,无论模板元编程中的将计算提前到编译器,还是编译器多态(或者叫静态多态), 都是非常漂亮聪明的应用, 在<<Modern C++ Design>>有着极好的体现。  回复  更多评论
      
    # re: C++模板类的三种特化[未登录]
    2007-07-16 16:11 | longshanks
    如果这样分的话,还应该有第四种特化:
    template<typename T1, typename T2>
    class X {...};

    template<typename T>
    class X<T, int> {...};
    以及2、3、4的混合
    template<typename T>
    class X<T, T*> {...}
    template<typename T>
    class X<vector<T>, T&> {...};
    ...
    更极端的,这样的特化是否该归为第5类呢:
    template<typename T>
    class Y;
    template<typename R, typename P1, typename P2>
    class Y<R (P1, P2)> {...};//针对带两个参数,有返回值的函数类型特化

    实际上,3仅仅是局部特化结合template-template parameter的一个应用。算不上一“种”特化。
    总的来说,还是C++标准中的分类更加清晰。

    另外,根据C++标准术语,应该是“类模板”(class template),而不是“模板类”。一般认为,“模板类”是模板实例化(特化)后的类:
    vector<int>  回复  更多评论
      
    # re: C++模板类的三种特化
    2007-07-16 21:26 | SmartPtr
    to longshanks

    本文的目的其实并不是试图对C++的模板特化做一下全面的分类, 而是针对自己所遇到的,觉得比较有意思的,对于一个模板参数所能够做到的特化,并不想对C++中的全特化,偏特化有所混淆。当然,之间也得到了大家不少有价值的看法。尤其对于您所举的这个例子:
    template<typename T>
    class Y;
    template<typename R, typename P1, typename P2>
    class Y<R (P1, P2)> {...};//针对带两个参数,有返回值的函数类型特化

    是我之前所没有想到的,我只考虑了数据类型并没有考虑到函数类型,但是我想参考针对数据类型所做的分类,可以得到函数类型对应平行的分类。比如对于这个例子,应该可以理解为第三种:特化为另外一个类(函数)模板。

    PS:
    谢谢关于模板类,类模板概念的澄清,原文已修改  回复  更多评论
      
    # re: C++类模板的三种特化
    2007-07-19 14:11 | shen126
    template<class T>
    class Compare<T*>
    {
    public:
    static bool IsEqual(const T* lh, const T* rh)
    {
    return Compare<T>::IsEqual(*lh, *rh);
    }
    };

    int _tmain(int argc, _TCHAR* argv[])
    {

    system("pause");
    return 0;
    }
    -----
    为什么这段代码在VS2005里编译出错了呢,难道不支持,还是需要打开什么特殊开关符吗?
      回复  更多评论
      
    # re: C++类模板的三种特化
    2007-07-19 14:12 | shen126
    Error 1 error C2143: syntax error : missing ';' before '<' e:\vs_projects\stltest1\stltest1\stltest1.cpp 7
      回复  更多评论
      
    # re: C++类模板的三种特化
    2007-07-20 01:03 | SmartPtr
    template<class T>
    class Compare<T*>
    {
    public:
    static bool IsEqual(const T* lh, const T* rh)
    {
    return Compare<T>::IsEqual(*lh, *rh);
    }
    };
    是模板特化, 你当然需要在之前定义其泛化版本  回复  更多评论
     
  • 相关阅读:
    并行fp-growth图解(mahout)
    Sqoop的安装与使用
    深入理解Hadoop集群和网络
    datanode与namenode的通信原理
    Hadoop添加节点datanode(生产环境)
    Hadoop中HDFS工作原理
    实现hadoop中的机架感知
    hadoop集群监控工具Apache Ambari安装配置教程
    sdn测量综述
    SDN测量论文粗读(三)9.24
  • 原文地址:https://www.cnblogs.com/cutepig/p/1389479.html
Copyright © 2011-2022 走看看