当前位置:   article > 正文

C++模板特化

c++模板特化

模板特化

        在学习模板的时候我们用模板来解决了一个add模板函数,实现不同类型的传参相加,实践证明,模板函数比普通函数好用。那么现在如果我们要新增一个需求,就是如果传入的是两个string类型的参数,我们不要简单的拼接,我们要在两个字符串之间添加一个空格,显然模板函数已经无法满足我们的要求,解决方法就是使用模板特化,简单说就是模板的一个特殊化,当传参为两个string类型的时候,不调用模板函数,而是调用特化模板函数,传入其它类型的时候,仍然使用模板函数,如下示例:

  1. template <typename T>
  2. T add(T a, T b)
  3. {
  4.        return a+b;
  5. }
  6. template<> string add(string a,string b)
  7. {
  8.        string c=" ";
  9.        return a+c+b;
  10. }
  11. int a=5,b=6;
  12. string e="hu",f="daizhou";
  13. cout<< add(a,b)<<endl;
  14. cout<< add(e,f)<<endl;

模板特化的实现类似于函数重载,模板特化发生在编译时,而非运行时,所以效率高。

        特化的模板声明,前面一般是template<>,方括号为空。当同时出现同名、同参的普通函数和特化模板函数,及同名模板函数时,编译器优先使用普通函数,再是特化模板函数,最后才是模板函数。

全特化

        特化分为全特化和偏特化,全特化即把模板的所有参数都指定类型,示例如下,定义了一个类和他的全特化类,值得注意的是,泛化模板类的类名后面不需要类型,而特化模板需要在类名后面指定类型。

  1. template<typename T1,typename T2>  //泛型模板,实体省略
  2. template<> class peple<int,int>   //全特化
  3. {
  4.        public:
  5.        void print(int a,int b)
  6.        {
  7.          cout<<"typename<>  a = "<< a <<"  b= "<< b <<endl;
  8.         }
  9. };

偏特化

        偏特化就是特化部分参数,如下示例,泛型模板2个参数都是模板,特化模板则将第二个参数固定,第一个模板仍然泛化。其实就是一个模板类中有多个参数类型,这些参数用到了模板参数,也用到了普通类型。

常规类型指定

  1. template<typename T1,typename T2> class peple  //泛型模板,实体省略
  2. template< typename T >  class peple<T,int>      //部分特化模板
  3. {
  4. public:
  5. void print(T a,int b)
  6. {
  7. cout<<"typename<>  a = "<< a <<"  b= "<< b <<endl;
  8. }
  9. };

指针特化

        如下示例,将第二个参数固定为普通类型的指针,第一个参数仍然是泛化模板类型,无论是什么类型的特化,模板类的类型指定与内部函数的传参类型无直接关联,如下列中,第2个参数是指针,但内部的print函数可有可无形参,即使有,也可以不同。实际上这种偏特化完全可以将指针替换成引用,或者前面添加const,有const和没const的匹配是不同。

  1. template<typename T>  class peple<T, double *>
  2. {
  3.   public:
  4.      void print(int a,double b)
  5.      {
  6.        cout<<"typename<>  a = "<< a <<"  b= "<< b <<endl;
  7.       }
  8. };

模板偏特化模板

模板特化,指模板类的类型是另外一个模板类,如array、vector、list等。

  1. template<typename T>  class peple<vector<T>>
  2. {
  3. public:
  4. void print(void)
  5. {
  6. cout<<"peple<T1 a,array<T2,int k>" << endl;
  7. }
  8. }
  9. int main(void)
  10. {
  11. peple<vector<int> > aa;
  12. aa.print();
  13. }

模板函数重载

        函数重载和模板函数重载有些类,特化的调用的特点是在函数后面用<>指定传参类型。有一个事实,就是模板函数仅支持全特化但是不支持偏特化,理由是因为函数重载先出现,而函数重载就已经能够实现函数偏特化的效果,一旦两个都支持,那就涉及优先级的问题,所以c++作者的选择是不允许函数模板偏特化。函数模板重载如下:

  1. template<typename T1>  void func(T1 a)
  2. {
  3. cout<< "func1 a= "<< a << endl;
  4. }
  5. template<typename T1>  void func(T1 *a)
  6. {
  7. cout<<"func2 *a= " << *a<<endl;
  8. }
  9. double c=5.6,d=7.8;
  10. func<double>(c);
  11. func<double *> (&d);//不支持偏特化

编译器匹配规则

第①步:匹配非模板函数,即普通函数,如果匹配到就执行,匹配不到进行下一步;

第②步:匹配基础泛化版本函数,匹配不到就报错,匹配到了再进入下一步。

第③步:匹配全特化函数,如果有就执行,无就执行上一步的基础泛化版本。

细节:模板函数的特化版本,不参与函数重载,即可以有完全特化版本的函数与普通函数同名、同参,在调用的时候,普通调用就是func(a);而泛化版本的调用时func<int>(a);

特化总结

        到此我们特化的研究就暂告于段落,特化实际上是我们帮编译器去做了类型推导的工作,告诉编译器不用去推导了,直接使用我给出的这个。

        模板特化和模板实例化两个概念注意区分,模板实例化指的是具体确定模板参数的类型T,模板特化就是前面一直在学的给出具体类型,本质上模板全特化就是一种实例化,而偏特化则不是,偏特化只是把模板类型的可能性压缩了,如模板偏特化成了指针,那么后面匹配的时候就只能是一个指针类型,因为模板函数并不是实例,普通函数是一个实例,所以他们不会冲突。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/576717
推荐阅读
相关标签
  

闽ICP备14008679号