C++中template模板何时被实例化?类模板实例化时机相关问题
问题相关代码
template <typename T> struct Pow{ T operator()(T const& x) const{ return x * x; } }; void func(Pow<double>); // Pow<double> instantiated here? void func(Pow<int>){} // Pow<int> instantiated here? int main(){ Pow<int> pi; // instantiated here? func(pi); // Pow<int> instantiated here }
问题解答
1. 模板的具体实例化时机是什么?
类模板默认采用按需隐式实例化规则,只有当编译器必须拿到类的完整定义才能完成编译时,才会触发实例化,常见触发场景包括:
- 创建该模板类的实体对象(比如示例中
Pow<int> pi;的位置) - 需要获取该类类型的大小、或者访问类的成员变量/成员函数
- 以该类为参数/返回值的函数被ODR使用(即需要生成该函数的实际二进制代码)
- 手动写显式实例化语句,比如
template struct Pow<int>;
如果仅需要类的前向声明就能满足编译需求的场景,不会触发实例化。
2. Pow<int>是否在声明func(Pow<int>)时就被实例化?
不会。函数声明阶段仅需要确认Pow<int>是合法存在的类型即可,不需要类的完整定义,所以不会触发实例化。哪怕你写完了func(Pow<int>)的函数实现,只要这个函数从来没有被实际调用、取地址等使用行为,编译器也不会生成该函数的二进制代码,自然也不需要实例化Pow<int>。
3. 如果我没有在main()中使用Pow<int>,那么func将其作为参数类型使用的场景是否会触发该模板的实例化?
看func(Pow<int>)是否被实际使用:
- 如果该函数仅做了声明/定义,没有任何调用、取地址等需要生成二进制代码的操作,不会触发实例化
- 如果该函数被ODR使用(比如在其他代码位置调用了它,或者把它的地址赋值给了函数指针),编译器需要生成函数的完整实现,此时需要确认参数类型
Pow<int>的大小、内存布局等信息,就会触发实例化
内容的提问来源于stack exchange,提问作者Itachi Uchiwa
相关产品推荐
相关产品推荐

