详谈模板实例化和具体化

这里以类模板为例,函数模板可以类比。
其实实例化(instantiation)和具体化(specialization)这两个东西应该分开来谈,实例化的是对象,而具体化的是模板(类似于声明)。
template class Pair
{
     ...
};
Pair ii;     //implicit instantiation    隐式 实例化对象

template class Pair;     //explicit instantiation    显式 实例化对象

template <> class Pair     //explicit specialization   显式 具体化模板
{
     ...
};

template class Pair     //partial specialization   部分 具体化模板
{
     ...
};
  1. Instantiation
一定记住一点,实例化的是对象。在面向对象的第一天就知道: 对象是类的实例化!始终记住这点!
    • Implicit Instantiation
隐式实例化就像我们用类名实例化对象一样,唯一不同的是需要在类模板后面指定该对象所需的类型参数,跟函数调用类似。
Pair ii;     //implicit instantiation
    • Explicit Instantiation
当使用关键字template并指出所需类型来声明类时,编译器将生成类声明的显式实例化。声明必须位于模板定义所在的名称空间中。
template class Pair;     //general Pair class
在这种情况下,虽然没有创建或提及类对象,编译器也将生成类声明(包括方法定义)。和隐式实例化一样,也将根据通用模板来生成具体化。
想起了之前在函数模板部分中的这样一句话: 试图在同一文件(或转换单元)中使用同一种类型的显式实例化和显式具体化将出错。意思就是说使用显式实例化可以在模板声明部分进行实例化,而后试图具体化一个同种类型的模板将报错,这样可以避免代码臃肿,因为模板并不能减少代码量,只是程序员将这部分工作交给了编译器罢了。
另:用显式实例化可以实现 单例模式,用显式实例化生成一个对象,然后将构造函数私有化,方法用static修饰,对象用static修饰,保证外部不能直接new出对象,必须通过方法实例化,确保了对象的唯一性。单例模式的具体实现请详见模式设计。
  1. Specialization
先说说为什么要有具体化,顾名思义,就是通用模板不能处理所有的类型,所以才引入具体化。注意,具体化的都是模板!
举个例子:假设已经为用于表示排序后的数组定义了一个模板,假设模板使用>运算符来对值进行比较。对于数字,这管用;如果T表示一种类,则只要定义了T: :operator>( )方法,这也管用;但是如果T是有const char * 表示的字符串,这将不管用。实际上,模板倒是可以正常工作,但字符串将按地址(按照字母顺序)排序。这要求类定义使用strcmp( ),而不是>来对值进行比较。在这种情况下,可以提供一个显式模板具体化,这将采用具体类型定义的模板,而不是为泛型定义的模板。当具体化模板和通用模板都与实例化请求匹配时,编译器将使用具体化版本。 [《C++ Primer Plus》6th P582]
引入模板的初衷就是应用泛型编程,但是引入新的必须要能够很好的处理旧的,如果一个模板只能解决很少一部分类型,那些不能处理的类型需要重新定义一个模板,那将是一件多么麻烦的事。所以“Specialization”很好的为我们解决了这个问题(基本上能够使所有类型适应该模板)。
    • Explicit Specialization
所有的具体化都是在通用模板的基础上引申出来的,所以我们看待新事物的时候,要用类比的方式,结合旧的看待新的。
template class Pair     //general template
{
     ...
};

template <> class Pair     //specialization template
{
     ...
};
先注意一点,我们在使用模板实例化对象的时候其实已经使通用模板具体化为了一个具体化模板了:
Pair MyPair;
观察Highlight部分,其实通用模板就是在类模板声明的时候给了模板类型参数,使通用模板具体化为了一个为实现特定类型功能的模板。
再对比Underline部分,在声明通用模板时,应该首先声明类型参数(就像函数应该先给它参数一样),而声明具体化模板,可以看成是“给它的类型参数为空”,因为它的参数都在类名的后面(即:Highlight部分给出了)。
    • Partial Specialization
明白了显式具体化之后再来看部分具体化就容易多了,部分具体化其实就是为了解决显式(全部类型参数)具体化的弊端,只需要指定部分类型参数:
template  class Pair     //general template
{
     ...
};

template class Pair     //partial specialization template
{
     ...
};
部分具体化就是在模板声明时给出部分类型参数,如这里就指定了第二个类型参数为int。在需要具体的模板实例化对象时在指定第一个类型参数即可。

你可能感兴趣的:(C++)