C++模板编程


697 浏览 5 years, 4 months

2.2 编译器处理模板的原理

版权声明: 转载请注明出处 http://www.codingsoho.com/

编译器处理模板的原理

为了理解模板的复杂性,必须学习编译器处理模板代码的原理。当编译器遇到模板方法定义的时候,编译器进行语法检查,但是并不编译模板。编译器无法编译模板定义,因为编译器不知道要使用的类型是什么。编译器在不知道X和Y的类型的情况下无法为X=Y这样的语句生成代码。

当编译器遇到一个实例化的模板的时候,例如Grid<int> myIntGrid,编译器会将模板类定义中的每一个T替换为int,从而生成Grid模板的int版本代码。

当编译器遇到这个模板的另一个实例时,例如Grid<SpreadsheetCell> mySpreadsheet,编译器为SpreadsheetCell生成另一个版本的Grid类。

编译器生成代码的方式就好像语言不支持模板的时候程序员会编写代码的方式:为每一个元素类型编写一个不同的类。这里没什么神奇之处;模板只是自动完成一个很容易令人感到厌烦的过程。如果在程序中没有将类模板实例化为任何类型,那么类方法定义也不会被编译。

这个实例化的过程也解释了为什么需要在定义中的多个地方使用Grid<T>语法。当编译器为某一个特定类型实例化模板的时候,例如int,编译器将T替换为int,使得Grid<int>成为类型。

1.选择性实例化

编译器只会为那些实际为某个类型调用的类方法生成代码。例如,给定前面定义的Grid模板类,假设在main()中编写这段代码(而且只有这段代码):

Grid<int> myIntGrid;
myIntGrid.setElementAt(0,0,10);

编译器只会为int版本的Grid生成无参构造函数、析构函数和setElementAt()方法的代码。编译器不会为其他方法生成代码,例如复制构造函数、赋值运算符和getHeight() 。

2.模板对类型的要求

当您编写与类型无关的代码的时候,您肯定对这些类型有一些假设。例如,在Grid模板中,假设了元素类型(用T表示)会有赋值运算符,因为有这一行代码:mCells[x][y]=inElem。类似地,还假设这个类型会有一个默认构造函数,允许创建一个元素的数组。

如果在程序中试图用一个不支持模板使用的所有操作的类型对模板进行初始化,那么这段代码无法成功编译,而且错误消息几乎总是非常晦涩难懂。然而,就算要使用的类型不支持所有模板代码所需的操作,还可以利用选择性实例化使用某些方法,而避免使用另一些方法。

例如,如果试图对没有赋值运算符的对象创建一个网格,但是永远都不调用这个网格的setElementAt()方法,那么这段代码也能正常工作。然而,只要调用了setElementAt()方法就会产生编译错误。