知识点:
在显式实例化模板类时,模板类并不会进行完全的实例化。更具体的,模板类的成员函数当且仅当被调用时才进行实例化;不被调用的成员函数,编译器不对它进行实例化,甚至不做语义检查。
例子:
定义一个模板类BinGather,其模板形参为class T,包含两个成员变量a和b,并拥有3个成员函数print和compare以及显式构造函数。代码如下:
#include<iostream>
using namespace std;
template<class T>
class BinGather
{
private:
T a,b;
public:
BinGather(T x,T y):a(x),b(y) //构造函数
{
}
void print() //打印数据到屏幕
{
cout<<"Elements are ("<<a<<") and ("<<b<<")."<<endl;
}
bool compare() //比较元素大小,输出较大值。使用了strcmp函数
{
cout<<"("<<(strcmp(a,b)>0?a:b)<<") is bigger.\n";
return strcmp(a,b);
}
};
int main()
{
BinGather<int> bX=BinGather<int>(10,20);
bX.print();
//bX.compare(); //#1 bX是int的二元组,int并没有strcmp函数
BinGather<const char*> bY=BinGather<const char*>("abc","abbd");
bY.print();
bY.compare();
system("pause");
return 0;
}
代码比较简单,#1处的代码如果没有注释掉,编译时一定会报错,错误信息为:
Error 1 error C2664: 'strcmp' : cannot convert parameter 1 from 'int' to 'const char *' e:\codes\moderncppdesign\02incompleteinstantiation\02.cpp
这是因为程序在#1调用了BinGather<int>的成员函数compare,编译器将对compare函数做语义检查,而int并没有strcmp函数,所以编译出错。
如果将#1处的代码注释掉,再次编译并不报错,运行也正常,结果为:
Elements are (10) and (20).
Elements are (abc) and (abbd).
(abc) is bigger.
请按任意键继续. . .
分析原因,正是由于程序没有调用BinGather<int>的成员函数compare,因此该函数不会被实例化,编译器也不对它做语义检查。
『模板类的不完全实例化』这一特性有两个好处。一方面,它一定程度上缓解了模板类实例化为普通类所导致的“代码膨胀问题”;另一方面,它为使用policy classes的程序员带来了不少的自由度。