欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

模板的特化和偏特化以及相关理解

程序员文章站 2024-01-14 17:27:52
...

写在前面:

主要是对于模板的特化和偏特化做一个总结以及个人的理解。

为什么需要特化或者偏特化:

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


对于一般的类模板,模板参数T是在编译的时候编译器根据你传入的参数自动生成对应的代码,这样的好处是显而易见的对于同样的处理或者同样的操作过程可以很好的封装在一个模板当中,根据传入的不同的参数具体实现对于不同的数据或者对象的操作。
但是这样也是有些问题是解决不了的,当有些数据类型或者对象不支持和其他的数据类型或者对象相同的操作的时候,就需要用其他的方式去实现同样一个过程,这个时候仅仅改变一个模板参数T是远远不行的。


而特化和偏特化其实就应对这样的情况。
对于某些特殊的数据类型,需要不同的实现方式的时候,就可以采用这样的方式。

举例

下面是类模板,全特化和偏特化的一个简单的例子:

template<typename T1, typename T2>  
class Test  
{  
public:  
    Test(T1 i,T2 j):a(i),b(j){cout<<"模板类"<<endl;}  
private:  
    T1 a;  
    T2 b;  
};  

template<>  
class Test<int , char>  
{  
public:  
    Test(int i, char j):a(i),b(j){cout<<"全特化"<<endl;}  
private:  
    int a;  
    char b;  
};  

template <typename T2>  
class Test<char, T2>  
{  
public:  
    Test(char i, T2 j):a(i),b(j){cout<<"偏特化"<<endl;}  
private:  
    char a;  
    T2 b;  
};  


Test<double , double> t1(0.1,0.2);  
Test<int , char> t2(1,'A');  
Test<char, bool> t3('A',true);  

可以看出全特化就是将模板的参数写死,针对这样一种具体的实现,告诉编译器要去生成的是这段代码,而非是将参数传入模板当种简单的替换。
偏特化就属于两者之间,有某些参数被写定,有些参数还是T根据实例化的时候去替换。


注意:而对于函数模板,却只有全特化,不能偏特化。

总结:

1.对于不同的数据类型要采用同样的形式进行封装(泛型),可以采用这样的方式,这样一个模板就可以处理多样的数据,对于用这个模板的人来说就很方便和简单。
2.在模板声明定义的下面接着类似的声明和定义全特化和偏特化的模板就可实现这样的功能。
3.对于类模板定义和实现只能放在同一个.cpp文件当中,不要将定义放在.h文件具体的实现放在.cpp当中,这和一般的类不同。原因如下:一般的类来说,可能会被多个文件include将所有的东西写在头文件里就会被多次引入,这样会使得代码过于庞大,并且一旦这个类的某个实现改动将导致所有引入这个头文件的文件需要重新编译,增大了其他文件对于这个类的依赖性,对于非常大的工程来说这是极其的耗时的。这是一般的类为什么需要分.h和.cpp的原因。而类模板截然不同,因为模板类对于程序实际是不存在的,仅仅是给编译器看的,告诉编译器当出现这样的情况时可以生成怎样的代码。因此只需要一份即可,如果分开写,被include的时候只看得到定义看不到具体的实现还是没有用,因为.cpp文件不会被include所以编译器看不到。
4.类模板的静态成员变量近属于实例化后的类,不同的模板实例不共享同一个静态成员变量。


模板函数的问题

下面总结一些关于模板函数的理解。

template <class T>
void sort(T element[], unsigned int count)
{
//具体的实现
}

那么对于传入的具体的element[]模板函数是怎么作用的呢?
首先,模板函数其实就是定义了一系列的重载的函数,要使用这些函数需要先实例化。
实例化分为隐式的和显示的。一般是隐式的。编译器会根据调用时的参数自动的将函数模板实例化为具体的函数。这个过程叫做模板实参数推演。
当编译器无法从传入的参数来确定多调用的模板函数的时候,就需要显示的实例化模板函数。

sort<int>(a,100);