显式实例化(仅限 C++)

您可以明确告知编译器何时应该根据模板生成定义。 这称为 显式实例化。 显式实例化包括两种格式: 显式实例化声明显式实例化定义

C++11

显式实例化声明

在 C++11 标准中引入了显式实例化声明功能。 通过此功能,您可以禁止对模板特殊化或其成员进行隐式实例化。 extern 关键字用于指示显式实例化声明。 此处 extern 的用法与存储类说明符的用法不同。

显式实例化声明语法

读取语法图跳过可视语法图 extern template 模板声明

如果模板的显式实例化定义存在于其他转换单元中或同一文件中的更高版本中,那么可以为模板特殊化提供显式实例化声明。 如果一个转换单元包含显式实例化定义,那么其他转换单元可以使用特殊化,而不必多次实例化该特殊化。 以下示例演示了此概念:

//sample1.h:
template<typename T, T val>
union A{
   T func();
};
extern template union A<int, 55>;

template<class T, T val>
T A<T,val>::func(void){
   return val;
}

//sampleA.C"
#include "sample1.h"

template union A<int,55>;

//sampleB.C:
#include "sample1.h"

int main(void){
   return A<int, 55>().func();
}

sampleB.C 使用 sampleA.CA<int, 55>().func()的显式实例化定义。

如果已声明函数或类的显式实例化声明,但程序中的任何位置都没有相应的显式实例化定义,那么编译器将发出错误消息。 请参阅以下示例:

// sample2.C
template <typename T, T val>
struct A{
   virtual T func();
   virtual T bar();
}

extern template int A<int,55>::func();

template <class T, T val>
T A<T,val>::func(void){
   return val;
}

template <class T, T val>
T A<T,val>::bar(void){
   return val;
}

int main(void){
   return A<int,55>().bar();
}
使用显式实例化声明时,请注意以下限制:
  • 可以在显式实例化声明中命名静态类成员,但不能命名静态函数,因为在其他转换单元中无法通过名称访问静态函数。
  • 类的显式实例化声明不等同于其每个成员的显式实例化声明。
C++11

显式实例化定义

显式实例化定义是模板专业化或其成员的实例化。

显式实例化定义语法

读取语法图跳过可视语法图 template 模板声明
以下是显式实例化定义的示例:
template<class T> class Array { void mf(); };
template class Array<char>;       /* explicit instantiation definition */
template void Array<int>::mf();   /* explicit instantiation definition */

template<class T> void sort(Array<T>& v) { }
template void sort(Array<char>&); /* explicit instantiation definition */

namespace N {
   template<class T> void f(T&) { }
}

template void N::f<int>(int&);
// The explicit instantiation definition is in namespace N.

int* p = 0;
template<class T> T g(T = &p);
template char g(char);           /* explicit instantiation definition */

template <class T> class X {
   private:
      T v(T arg) { return arg; };
};

template int X<int>::v(int);    /* explicit instantiation definition */

template<class T> T g(T val) { return val;}
template<class T> void Array<T>::mf() { }

模板的显式实例化定义位于您定义模板的同一名称空间中。

访问检查规则不适用于显式实例化定义中的自变量。 显式实例化定义中的模板参数可以是专用类型或对象。 在此示例中,您可以使用显式实例化定义 template int X<int>::v(int) ,即使将成员函数声明为专用也是如此。

当您显式实例化模板时,编译器不会使用缺省参数。 在此示例中,您可以使用显式实例化定义 template char g(char) ,即使缺省自变量是类型为 int的地址也是如此。

注意: 在函数模板或类模板的成员函数的显式实例化中,不能使用 inlineC++11constexprC++11 说明符。
C++11 开始

显式实例化和内联名称空间定义

内联名称空间定义是具有初始 inline 关键字的名称空间定义。 内联名称空间的成员可以显式实例化或专用,就像它们也是外层名称空间的成员一样。 有关更多信息,请参阅 内联名称空间定义 (C++11)

C++11 结束