c++模板特化和偏特化

模板的好处在于使得一个数据结构或算法的程序只需写一次,就能够使用各种具体数据类型(int,float.......等)。

这样写的模板固然有普遍适用性,但是由于针对各种数据类型都采取相同的处理方式,但是数据类型之间多多少少还是有一些区别,这样有的时候就不能兼容或者效率不是很高。

举个类模板不太兼容的经典例子:(比较大小)

//模板类
template<typename T> 
class Test
{
    static bool comp(T num1, T num2)
    {
        return (num1<num2)?true:false;
    }
当我们传入的数据类型是int、double这些类型的时候还可以正常使用。
但是假如我们传入了一char类型,(我们都知道char类型比较大小必须用到strcmp函数,)那这时候这个类模板就无法兼容,就得需要专门特化一个char型的模板

//特化后的char型模板,传入的是字符串类型时,会优先调用特化后的模板(其实这个特化后的代码和原来关系不大,这里先不用纠结特化代码怎么写,下面会有详细的特化介绍,知道这回事就可以了)
template < >
class Test
{
    static bool comp(T num1, T num2)
    {
        return strcmp(left, right);  //和上一段代码的不同之处
    }

引言:

      偏特化和特化的不同之处在于,特化将所有的模板参数都固定下来,因而对类模板、函数模板特化的结果不再是模板,因为它不具有模板的可扩展性了,而是具有普通的类、普通的函数的性质。但是偏特化仍然保留了一部分的未定参数,仍然具有一定程度上的可扩展性,这使得偏特化后的结果仍然是模板。

全特化:

             模板类的类型全部都已经明确化,全特化的类中的函数可以与模板类不一样。

偏特化包含两种:

             1.模板中的模板参数没有被全部确定,需要编译器在编译时进行确定。

             2.在类型上加上const、&、*( cosnt int、int&、int*、等等)并没有产生新的类型。只是类型被修饰了。

 一:模板特化

注意:一个模板被称为全特化的条件:1.必须有一个主模板类(小tip:我们得将特化后的模板写在纯模板之后,否则会报错)  2.模板类型被全部明确化(区别于偏特化的部分明确化)

模板特化的固定格式:  前面有一个template<> 然后下面就是特化后的函数代码,(其实这样看来模板特化和新写一个函数(类)其实差别不大)

调用顺序:特化>偏特化>纯模板

1.函数模板特化

示例:(下面的例子来自于网上)

//模板函数,未经特化
template <class T>
int compare(const T &left, const T&right)
{
    return (left - right);
}


//特化后的函数(显而易见的就看出来特化后的代码和原来的有很大的不同)
template < >  //虽然这里面啥也不写,但是仍然得写上,这就是提示编译器和程序员的一个标志
int compare<const char*>(const char* left, const char* right)
{
    return strcmp(left, right);
}

 2.类模板特化

程序例子就不举了,文章开头那个例子就是。

几个注意点: 

来自于:https://www.cnblogs.com/qlee/archive/2011/06/27/2091523.html

* 如果类模板中含有静态成员,那么用来实例化的每种类型,都会实例化这些静态成员。

* 两个靠在一起的模板尖括号( > ) 之间需要留个空格,否则,编译器将会认为是在使用operator>>,导致语法错误。

* 特化的实现可以和基本类模板的实现完全不同。

* 类模板可以为模板参数定义缺省值,称为缺省模板实参,并且他们还可以引用之前的模板参数。

* 成员函数模板不能被声明为虚函数。


二:模板偏特化

  主要是类模板的偏特化,函数模板的偏特化没必要,因为可以通过重载来完成。

偏特化的条件:1.必须有一个主模板   2.模板类型被部分明确化

这里的语法形式和特化时的有明显的差异,由于类模板经过偏特化后仍然是模板,所以依然要以template<参数类型表>来开头


    1.类模板的偏特化

//纯模板,未偏特化
template<class T1, class T2>
class A
{
..............
}

//偏特化后的模板,可以看出T2被我们明确成为了int类型。
template<class T1>
class A<T1, int>  //区别之处
{
............
}


    2.函数模板的重载

        其实,对于函数而言,虽然不能偏特化,即不能再在函数名字后面像模板类一样搞个<typename T>出来,但是可以通过函数的重载(注意这里说的重载是指的模板重载,而不是普通意义的函数重载)来实现偏特化。

程序示例: 

//原模版
template <typename T1, typename T2>
bool test(T1 t1, T2 t2)
{
   return t1 < t2 ? t2 : t1;
}


//第一种偏特化
template <typename T1>
bool test(T1 t1, int t2)
{
   return t1 < t2 ? t2 : t1;
}

//第二种偏特化,偏特化成为一个指针或者引用类型
template<class T>
T *test(T *t1,T* t2)
{
      return (*t1>*t2)?t1:t2;
}

 

 

总结:

    1 来自:https://blog.csdn.net/m_buddy/article/details/72973207

    1.

    但是模板特化并不只是为了性能优化,更多是为了让模板函数能够正常工作,最典型的例子就是STL中的iterator_traits。algorithm中大多数算法通过iterator对象来处理数据,但是同时允许以指针代替iterator对象,这是为了支持C-Style Array。如果直接操作iterator,那么为了支持指针类型,每个函数都需要进行重载,因为指针没有::value_type类型。为了解决这个问题,STL使用了iterator_traits,并为指针类型进行转化,算法通过它来操作iterator,不需要知道实际操作的是iterator对象还是指针。

 

  1. template<typename IteratorClass> class iterator_traits

  2. ...

  3. template<typename ValueType> class iterator_traits<ValueType*>

  4. ...

  5. template<typename ValueType> class iterator_traits<ValueType const*>

  6. ...

后面两是针对指针类型的偏特化,也是偏特化的一种常见形式。

 

2.

非类型模板参数:

在编译期或链接期可以确定的常值。这种参数的类型必须是下面的一种:

a> 整型或枚举   例子:template<class T,int size>

b> 指针类型( 普通对象的指针,函数指针,成员指针 )

c> 引用类型( 指向对象或者指向函数的引用 )

其他的类型目前都不允许作为非类型模板参数使用

 

3.

偏特化(半特化)的类型可以是我们自定义的类型

// 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);
    }
};

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ad_m1n

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值