zoukankan      html  css  js  c++  java
  • C++模板的特化与偏特化

    http://cppblog.com/SmartPtr/archive/2007/07/04/27496.html

     (1) 类模板
    定义一个栈的类模板,它可以用来容纳不同的数据类型

    template <class T>
    class stack {
    private:
        list* top;
    public:
        stack();
        stack(const stack&);
        ~stack();
        void push(T&);
        T& pop();
        //
    };

    类模板的使用除了要在声明时指明模板参数外,其余均与普通的类相同,例如:

    stack<int> int_stack;
    stack<char> ch_stack;
    stack<string> str_stack;
    int_stack.push(10);
    ch_stack.push(‘z’);
    str_stack.push(“c++”);

    (2) 函数模板
    假设现在要定义一个max函数来返回同一类型(这种类型是允许比较的)两个值的最大者.

    模板函数的使用与普通非模板函数使用相同,因为模板函数的参数类型可以从其传入参数中解析出来

    template<class T>
    T mymax(const T&t1, const T&t2)
    {
        return t1 < t2 ? t2 : t1;
    }
    
    void main()
    {
        int t1 = 1, t2 = 3;
        cout << mymax(t1, t2);
    }

    3.模板的特化
    (1)   类模板特化
    有时为了需要,针对特定的类型,需要对模板进行特化,也就是特殊处理.例如,stack类模板针对bool类型,因为实际上bool类型只需要一个二进制位,就可以对其进行存储,使用一个字或者一个字节都是浪费存储空间的.

    template <class T>
    class stack {};
    template < >
    class stack<bool> { //// };

    上述定义中template < >告诉编译器这是一个特化的模板。

    (2) 函数模板的特化
    看下面的例子

    main()
    {
      int highest = mymax(5,10);
      char c = mymax(‘a’, ’z’);
      const char* p1 = “hello”;
      const char* p2 = “world”;
      const char* p = mymax(p1,p2);
    }

    前面两个mymax都能返回正确的结果.而第三个却不能,因为,此时mymax直接比较两个指针p1 和 p2 而不是其指向的内容.
    针对这种情况,当mymax函数的参数类型为const char* 时,需要特化。

    template <class T>
    T mymax(const T t1, const T t2)
    {
       return t1 < t2 ? t2 : t1;
    }
    
    template <>
    const char* mymax(const char* t1,const char* t2)
    {
       return (strcmp(t1,t2) < 0) ? t2 : t1;
    }

    现在mymax(p1,p2)能够返回正确的结果了。(这个例子在扯淡,vs2015运行没问题)

    模板为什么要特化,因为编译器认为,对于特定的类型,如果你能对某一功能更好的实现,那么就该听你的。

    模板分为类模板与函数模板,特化分为全特化与偏特化。全特化就是限定死模板实现的具体类型,偏特化就是如果这个模板有多个类型,那么只限定其中的一部分。

    4.模板的偏特化
    模板的偏特化是指需要根据模板的某些但不是全部的参数进行特化,或者将T偏特化为T* 也是属于偏特化
    (1) 类模板的偏特化
    例如c++标准库中的类vector的定义

    template <class T, class Allocator>
    class vector { //// };
    template <class Allocator>
    class vector<bool, Allocator> { ////};

    这个偏特化的例子中,一个参数被绑定到bool类型,而另一个参数仍未绑定需要由用户指定。
    (2) 函数模板的偏特化

      (模板函数不能偏特化,但是可以重载。)为什么不能偏特化?
      严格的来说,函数模板并不支持偏特化,但由于可以对函数进行重载,所以可以达到类似于类模板偏特化的效果。
      template <class T> void f(T);  (a)
      根据重载规则,对(a)进行重载
      template < class T> void f(T*);  (b)

    5.模板特化时的匹配规则
    (1) 类模板的匹配规则
    最优化的优于次特化的,即模板参数最精确匹配的具有最高的优先权
    例子:

    template <class T> class vector{////}; // (a)  普通型
    template <class T> class vector<T*>{////};  // (b) 对指针类型特化
    template <>   class vector <void*>{////};  // (c) 对void*进行特化

    每个类型都可以用作普通型(a)的参数,但只有指针类型才能用作(b)的参数,而只有void*才能作为(c)的参数

    (2) 函数模板的匹配规则
    非模板函数具有最高的优先权。如果不存在匹配的非模板函数的话,那么最匹配的和最特化的函数具有高优先权
    例子:

    template <class T> void f(T);  // (d)
    template <class T> void f(int, T, double); // (e)
    template <class T> void f(T*);  // (f)
    template <> void f<int> (int) ; // (g)
    void f(double);  // (h)
    bool b;
    int i;
    double d;
    f(b); // 以 T = bool 调用 (d)
    f(i,42,d) // 以 T = int 调用(e)
    f(&i) ; // 以 T = int* 调用(f)
    f(d);  //  调用(g)

    参考effective c++条款25

    class WidgetImpl
    {
    public:
        WidgetImpl(){}
        ~WidgetImpl(){}
    private:
        std::vector<double>v;
    };
    
    class Widget
    {
    private:
        WidgetImpl* pImpl;
    public:
        void swap(Widget& other)
        {
            using std::swap;
            swap(pImpl, other.pImpl);
        }
    };
    
    //将std::swap特化,与STL容器保持一致,所有STL容器也都提供public swap成员函数和std::swap特化版本(用以调用前者)
    namespace std
    {
    template<>
    void swap<Widget>(Widget& a, Widget& b)
    {
        a.swap(b);
    }
    }
    //考虑类模板的情况
    template<class T>
    class WidgetImpl
    {
    public:
        WidgetImpl(){}
        ~WidgetImpl(){}
    private:
        std::vector<double>v;
    };
    
    template<class T>
    class Widget
    {
    private:
        WidgetImpl<T>* pImpl;
    public:
        void swap(Widget<T>& other)
        {
            using std::swap;
            swap(pImpl, other.pImpl);
        }
    };
    
    //以下代码偏特化函数模板(std::swap),但c++只允许对类模板偏特化,函数模板不能偏特化
    namespace std
    {
    template<class T>
    void swap<Widget<T>>(Widget<T>& a, Widget<T>& b)
    {
        a.swap(b);
    }
    }
  • 相关阅读:
    解决Access查询不区分大小写问题
    截取控件为图片
    解决VS+opencv中Debug版本与Release版本lib切换的问题
    OpenCv Mat操作总结
    机器学习实战-python相关软件库的安装
    图像数据归一化
    图像分割算法-GraphSeg算法
    Image Blending
    图像分割-图割理论与应用学习
    如何查看OpenCv的源代码
  • 原文地址:https://www.cnblogs.com/ljygoodgoodstudydaydayup/p/4213384.html
Copyright © 2011-2022 走看看