上文中的置入式模型inclusion model 保证所有用到的template都能被实例化。之所以有这层保障,是因为C++编译器会在template被使用时自动实现它。C++标准提供了另一种方式,可以手动将template实例化。这种方式称为显示实例化指令(explicit instantiation directive)。
1. 显示实例化(Explicit Instantiation)示例
可以为上文中有链接错误的工程,添加如下文件
//myfirstinst.cpp
//明确以double类型将print_typeof()实例化
template void print_typeof<double> (double const&);
这个显示实例化指令由两部分组成:
- 关键词 template
- 一个模板参数已被完全替换后的函数声明。
本例是对函数做显示实例化动作,也可以运用相同的手法对一个成员函数或一个static成员变数做显式实例化动作。如:
//明确以int类型对MyClass<>的构造函数进行实例化操作
template MyClass<int>::MyClass();
//明确以int类型对function template max<> 进行实例化操作
template int const& max (int const&, int const&);
也可以显式实例化一个类模板。这是一个简便做法,相当于要求编译器具体实例化该class template的所有可被实例化的成员,但不包括先前已被特化或已被实例化的成员:
//明确地以int类型对Stack<> class 进行实例化动作
template class Stack<int>:
//明确以 string类型对Stack<>的一部分成员进行实例化操作
template Stack<std::string>::Stack();
template void Stack<std::string>::push(std::string const&)
template std::string Stack<std::string>::top() const;
//不能对已被实例化的某个成员再次实例化,下面代码错误
template Stack<int> :: Stack();
明显的,程序中显式实例化语句只能出现一次,否则链接器报重复定义错误。这就要求我们必须非常仔细搞清楚该实例化哪些物体。
然而,显式实例化也有一些好处,实例化动作可以根据程序需求进行最佳调整。且避免包含巨大的头文件。另外,控制模板实例化在某个精确位置(object file)有时很有用,而自动实例化不能做到这一点。
2. 结合置入式模型(Inclusion model)和显式实例化(Explicit Instantiation)
为了进一步讨论该使用置入式模型或使用显式实例化,我们将模板的声明语句和定义语句分别置于两个不同的文件。通常会将这两个文件的扩展名看起来像头文件(可被包含)。这样,我们把先前myfirst.cpp改名为myfirstdef.hpp,并在首尾加上防止可重复包含的预处理指令。如下图
现在,我们
- 想使用置入式模型,可以简单地将定义式的头文件 stackdef.hpp包含进来。
//main.cpp
//stackdef.hpp
//stack.hpp
- 如果想要使用显式(明确)实例化,可以将声明语句所在的头文件 stack.hpp包含进来,且提供一个.c 文件,其中有必要的实例化指定,见下图,
//新增文件stack_inst.cpp 内容如下,
说明如下:
1)添加头文件stackdef.hpp
2) 添加4个显式声明
//main.cpp,修改如红线
其他两个文件内容不变