关键字“export”可能是在 C++ 标准中最常被忽略的特性了。下面我将讨论这个特性的语义和实现它的灵活性。
模板编制模型(Template compilation models)
不像一般的类和函数,在实例化一个模板时编译器必须看到这个模板的定义。这就是必须定义,而不仅仅是在 .h 文件中声明模板的原因。这就叫做“包含模型(inclusion model)”。
(至少)在理论上,标准 C++ 支持另外一种模板编制方法,即所谓的“导出模板(exported templates)”。直到最近,几乎所有的 C++ 编译器都忽略了导出模型(exported model)。在2002年,Comeau 提供了对导出模板的支持。另外还有其它几个编译器也支持这一特性,虽然他们并没有宣传。
导出模板(Exported templates)
在导出模型下,可以用 .cpp文件定义模板,单独对其编译,在 .h 文件将其声明为 export,然后在其它翻译单元中只要用 #include 引入这个 .h 文件就可以了。例如:
//func.h
export template <class T> void f(T t); // declaration
//func.cpp
template <class T> void f(T t)
{//definition
//..
}
//main.cpp
#include "f.h"
int main()
{
f(7); //instantiate void func<int>(7)
}
在实际使用时,事情并没有这么简单。在一个模板被实例化时,会在当前的上下文(也就是进行实例化的地方)和模板定义的上下文中查找依赖名称(也就是依赖于一个参数类型的名称,比如说在上面的例子中的 t)。如果查找不到模板的定义,编译器不能生成模板实例化的代码——不管模板是否被导出。
在 C++ 标准中这是一个要求。在导出模板中满足这一要求的唯一方法是使用一个“as-if”规则:编译器要么在目标文件中插入存根(stub),将代码生成推迟到一个较晚的阶段进行,要求必须在某种程度上使用一些技巧检索模板的定义。在任何一种情况下,包含导出模板定义的源文件必须在实例化时可用。因而,导出(export )不像一般的类和函数,它不是避免模板源代码发布的机制。
更多有关Comeau如何实现导出模板的信息,请查阅Comeau C++ Export Overview。