类模板的实例化时机与成员函数延迟实例化
类模板是在什么时候实例化的?类模板的成员函数是全部实例化还是按需实例化?什么是隐式实例化、显式实例化和extern模板?如何利用延迟实例化减少编译依赖和代码膨胀?
回答
我是大山
类模板实例化时机:当编译器遇到类模板的实际类型时(如vector<int>),会隐式实例化类的声明部分,但成员函数定义不会立即实例化——仅当调用时实例化。
按需实例化(Lazy Instantiation):
template<typename T>
class Wrapper {
public:
void f1() { /* 使用T的某些操作 */ }
void f2() { /* 使用T的其他操作 */ }
};
Wrapper<int> w; // 仅实例化类布局
w.f1(); // 实例化f1
// f2未调用,不实例化
隐式实例化:使用vector<int>时自动生成
显式实例化:template class vector<int>; —— 强制实例化所有成员(包括未调用的)
extern模板(C++11):extern template class vector<int>; —— 阻止当前TU实例化,避免多TU重复实例化
减少编译膨胀的策略:
- extern模板:将模板实例化放在一个.cpp中
- pimpl惯用法:将模板实现隐藏在非模板类(或虚函数接口)后
- 类型擦除:如std::function内部模板但外部统一接口
- 提取非模板代码:将不依赖模板参数的部分提取到非模板基类
- 限制实例化类型:static_assert配合类型列表
注意:static数据成员在类模板实例化时不会初始化,只在第一次使用时初始化。虚函数(若存在)总是实例化(因为vtable需要函数地址)。