模板实例化
模板实例化是到 C 语言的扩展之一,GCC 和 XL C/C 对其进行不同处理。编译器和链接程式需要确保每个模板实例在可执行程式中确实仅出现一次。这一节先讨论 GCC 如何处理模板实例化,然后讨论 XL C/C 中的可用选项。
GCC 3.2 不支持模板储存库的概念,模板储存库是存储模板实例的自动维护的位置。然而,GCC 3.2 提供了下列选项:
-frepo假如使用此选项,那么对于将模板实例化了的每个 .cc 文档,编译器将生成扩展名为 .rpo 的文档。这个 .rpo 文档包含相应对象文档中使用的模板实例化的清单。链接时,一些对象文档可能会重新编译和重新链接,以避免符号重复。-fno-implicit-templates使用这个选项,研发人员能够确定必须对哪些实例进行实例化。更有其他几个选项,如-fexternal-templates和-falt-external-templates,但是 GCC 3.2 中不支持这些选项。
XL C/C 中能够使用下列编译器选项:
-qtempinc使用这个选项,XL C/C 能够确定要实例化的模板代码,作为编译和链接过程的最后一步。这样做能够防止在最终的可执行程式或库中有重复的模板实例。该选项需要以特定方式组织源代码。也就是说,模板的声明和定义必须在单独的文档中。模板定义需要位于和头文档相同的目录中,并且拥有相同名称,但是具备 .cc(小写字母 c)后缀。否则,头文档必须使用
#pragma implementation("...")语句来标识相应的定义文档。例如,模板类 List 的声明和定义文档分别为List.h和List.cc。在 List.h 文档中,必须包含语句#pragma implementation("List.cc")。假如没有使用
-qtempinc指定目录,那么编译器将在当前目录中创建名为 tempinc 的目录,用他来保存将在模板中生成的信息。能够为这个目录选择自己的名称和位置,这样,当创建包含在不同目录中编译的对象文档的可执行程式时,能够使用相同目录。例如:
xlC -c foo.cc -qtempinc=../mytemplates
cd ..
xlC -o app app.cc src/foo.o qtempinc=mytemplates因为模板代码实际由编译器在链接时创建,所以当使用具备共享库的模板时(其中没有链接发生),就会出现问题。在 XL C/C Version 5 中,引入了选项
-qmkshrobj,当创建使用模板的共享对象时,该选项应该和-qtempinc一起使用。不使用makeC SharedLib而使用这些选项的长处是:编译器将自动包含并编译 tempinc 目录中的模板实例化。假如 XL C/C 检测到上述代码布局结构,那么他会自动启用
-qtempinc选项。假如想阻止这项操作,自己手工对模板进行实例化,那么能够使用选项-qnotempinc。还能够使用 #pragma define 指令强制执行实例化。例如,#pragma define(List); -qtemplateregistry假如不想更改代码布局或不想在头文档中添加 #pragma implementation 指令,那么能够使用此选项。他依赖于算法的先到先得类型。在编译单元对新的实例第一次进行实例化时,编译器将创建在个实例,并将记录保存在注册表文档中。 能够在该选项中指定这个注册表文档的名称。默认情况下,在当前目录中创建名为 templreg 的文档。当另一编译单元引用上一编译单元中相同的实例化或使用相同的注册表文档时,不再需要对该实例进行实例化。因此,只需为整个程式生成一个副本即可。
-qtemplateregistry 和 -qtempinc 选项是互斥的。指定 -qtempinc 则意味着 -qnotemplateregistry。然而,指定 -qnotempinc 并不意味着 -qtemplateregistry。
假如更改源代码,并且仅重新编译受影响的部分,那么 -qtemplaterecompile 选项将参考模板注册表,来确定是否对源文档进行更改需要重新编译其他编译单元。当将源文档更改为不再引用给定实例化及以前包含该实例化的相应对象文档时,需要执行这项操作。假如是这样,那么受影响的编译单元将自动重新编译。
假如需要的话,能够使用选项 -qnotemplaterecompile 禁用依赖单元的自动重新编译。从原始子目录移动对象文档的自动化构建过程就是这样的例子。
示例代码
下列示例代码说明了在 XL C/C 中如何处理 C 模板。
清单 1. 文档布局




