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

除非模板特殊化已显式实例化或显式特殊化,否则编译器仅在需要定义时才会为模板生成特殊化。 这称为 隐式实例化

C++0x 仅以 C++0x 开头。

当存在显式实例化声明时,编译器不需要为非类,非内联实体生成特殊化。

C++0x 仅限 C++0x 的结束。

如果编译器必须实例化类模板特殊化并且已声明该模板,那么还必须定义该模板。

例如,如果您声明一个指向类的指针,那么不需要该类的定义,并且将不会隐式实例化该类。 以下示例演示编译器何时实例化模板类:
template<class T> class X {
  public:
    X* p;
    void f();
    void g();
};

X<int>* q;
X<int> r;
X<float>* s;
r.f();
s->g();
编译器需要实例化以下类和函数:
  • 声明对象 r 时的 X<int>
  • X<int>::f() 成员函数调用 r.f()
  • X<float>X<float>::g() 在类成员访问函数调用 s->g()
因此,必须定义函数 X<T>::f()X<T>::g() 才能编译上述示例。 (编译器将在创建对象 r时使用类 X 的缺省构造函数。) 编译器不需要实例化以下定义:
  • X (当声明了指针 p 时)
  • 声明指针 q 时的 X<int>
  • 声明指针 s 时的 X<float>
如果涉及到指针转换或指向成员转换的指针,那么编译器将隐式实例化类模板特殊化。 以下示例对此进行了演示:
template<class T> class B { };
template<class T> class D : public B<T> { };

void g(D<double>* p, D<int>* q)
{
  B<double>* r = p;
  delete q;
}
赋值 B<double>* r = p 将类型为 D<double>*p 转换为类型 B<double>*; 编译器必须实例化 D<double>。 编译器在尝试删除 q时必须实例化 D<int>
如果编译器隐式实例化包含静态成员的类模板,那么不会隐式实例化这些静态成员。 仅当编译器需要静态成员的定义时,编译器才会实例化静态成员。 每个实例化的类模板特殊化都有自己的静态成员副本。 以下示例对此进行了演示:
template<class T> class X {
public:
   static T v;
};

template<class T> T X<T>::v = 0;

X<char*> a;
X<float> b;
X<float> c;
对象 a 具有类型为 char*的静态成员变量 v 。 对象 b 具有类型为 float的静态变量 v 。 对象 bc 共享单个静态数据成员 v

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

如果超负荷解析涉及函数模板或成员函数模板特殊化,那么编译器将隐式实例化该特殊化的声明。