当前位置:编程学习 > C/C++ >>

C++模板的特化

对模板特化的理解:
特化整体上分为全特化和偏特化,这一点大家都没有什么置疑,但是细分它们各包括哪几种状态就很难界定了,而且很多权威的书上都不一致,管它呢,反正我们能会用各种特化就可以了。
下面就谈谈我个人对特化的划分和定义:
所谓特化,就是将泛型的东东搞得具体化一些,从字面上来解释,就是为已有的模板参数进行一些使其特殊化的指定,使得以前不受任何约束的模板参数,或受到特定的修饰(例如const或者摇身一变成为了指针之类的东东,甚至是经过别的模板类包装之后的模板类型)或完全被指定了下来。
 
这是网上某个人的一些看法:
模板有两种特化,全特化和偏特化(局部特化)
模板函数只能全特化,没有偏特化(以后可能有)。
模板类是可以全特化和偏特化的。
全特化,就是模板中模板参数全被指定为确定的类型。
全特化也就是定义了一个全新的类型,全特化的类中的函数可以与模板类不一样。
偏特化,就是模板中的模板参数没有被全部确定,需要编译器在编译时进行确定。
在类型上加上const、&、*( cosnt int、int&、int*、等等)并没有产生新的类型。只是类型被修饰了。模板在编译时,可以得到这些修饰信息。
 
我个人也比较赞同这位仁兄的划分,全特化的标志就是产生出完全确定的东西,而不是还需要在编译期间去搜寻适合的特化实现,貌似在我的这种理解下,全特化的东西不论是类还是函数都有这样的特点,template <>然后是完全和模板类型没有一点关系的类实现或者函数定义,如果你要说,都完全确定下来了,那还搞什么模板呀,直接定义不就完事了?但是很多时候,我们既需要一个模板能应对各种情形,又需要它对于某个特定的类型(比如bool)有着特别的处理,这中情形下就是需要的了。
 
既然刚才提到了全特化的标志,那么再说说其他一些共性的东西:
一个特化的模板类的标志:在定义类实现时加上了<>,比如class A<int, T>;而在定义一个模板类的时候,class A后面是没有<>的
全特化的标志:template <>然后是完全和模板类型没有一点关系的类实现或者函数定义
偏特化的标志:template <typename T.....>,就是说还剩下点东西,不像全特化<>整得那么彻底
 
 
首先推荐两个不错的网址:
http://www.cnblogs.com/cutepig/archive/2009/02/12/1389479.html
http://read.newbooks.com.cn/info/175115.html
 
先说类模板的特化吧:
谁都没的说的全特化:
// general version
template<class T>
class Compare
{
public:
    static bool IsEqual(const T& lh, const T& rh)
    {
        return lh == rh;
    }
};
 
// specialize for float
template<>
class Compare<float>
{
public:
    static bool IsEqual(const float& lh, const float& rh)
    {
        return abs(lh - rh) < 10e-3;
    }
};
谁都没的说的偏特化:
template<class T1, class T2>
class A
{
}
 
template<class T1>
class A<T1, int>
{
接下来的特化种类,到底划归到全特化还是偏特化,你自己看着办吧,不过大致就以下这些了,逃不出我们的手掌心了:
特化为引用,指针类型:
// 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);
    }
};
特化为另外一个类模板:
// 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;
    }
};
混合型的:
template<typename T1, typename T2>
class X {...}; 
template<typename T>
class X<vector<T>, int&> {...}; //至于这里怎么都把T2搞没了变成只依赖一个模板参数T了的问题,大家别着急,我来告诉你个本质的东西,把我这么三点就可以了:1.模板参数个数一致;2.只要template <...>里面有东西不是<>,比如typename T,那么特化时就得用到T;3.不进行任何对模板参数的修饰也是不行的,比如template<typename T> class<T>{...},至少你也得搞个const T之类的吧,呵呵。下面是我搞出来的几种特殊情况,它们都是正确的:
template<typename T1, typename T2>
class X {};
template<typename T>
class X<vector<T>, T&> {};
template<typename T>
class X<vector<T>, int&> {};
template<>
class X<vector<double>, int&> {};
template<typename T1, typename T2, typename T3>
class X<map<T1,T2>, T3&> {};
最后,还有一种超级牛X的,在tr1里面用以实现function的,以前我都没见过还可以这么玩的:
template<typename T>
class Y;//这是在声明一个类模板,既然声明了,以后就得按这个规矩来,在我们之前的编程经验里,可以重复声明一个东西没问题,但是为同一个东东重复声明出不同的东西就不可以了,因此你就不能再声明诸如template<typename T1, typename T2> class Y;这样的声明了;其实没有什么是不能声明的,既然我们可以声明变量,声明函数,声明类,那么当然我们也可以声明函数模板或者类模板的。
template<typename R, typename P1, typename P2>
class Y<R (P1, P2)> {...};//针对带两个参数,有返回值的函数类型特化,这里R (P1,P2)是定义了一种类型,该类型是一个隐式的函数指针,返回R,参数为P1和P2,这种对函数指针的定义完全等同于R (*)(P1,P2),但是前一种定义很不常见,大家一般是不会注意到这个地方的。
 
好了,说了不少关于类模板的特化了,下面再简要说说函数模板的特化:
函数模板的特化只能是全特化,而不能是偏特化,因此对于函数的特化就比较简单了,就是重新搞一遍就可以了,举几个例子如下:
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;
}
 
但是你不能这么搞:
template <>
bool mymax(const char* t1,const char* t2)
{
   return (strcmp(t1,t2) < 0);
}
其实对于mymax这个模板函数的定义而言,是用一个模板参数控制了三个地方,那么你在特化的时候,就也需要用一个特定的类型修改那三处相应的地方,如果你非要返回bool,那么你只能再定义一个函数模板了:
template <class T>
bool mymax(const T t1, const T t2)
{
   return t1 < t2 ? t2 : t1;
}
问题又来了,大家都知道函数重载是不关心返回值的,而只关心参数个数以及类型是否不一致,不一致就是重载,但是对于模板函数而言,这个规矩不再成立,因为任何与模板相关的东西都只是个架子放在那里而已,只要它符合语法规则就可以了,这些架子只是在有人要调用它们时才
补充:软件开发 , C++ ,
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,