c++--模板--实例化
模板实例化的位置
注意,在最终的代码中,只有编译单元(一个.cpp文件就是一个编译单元),没有头文件之说,所以,即使你的模板放在头文件中,最终头文件也只是插入到元文件中作为一个编译单元。
所以模板的实例化是直接在每一个编译单元中实力化。
那么多而编译单元,如果实例化出相同的函数或者对象,怎么办?
链接时,链接器会保留其中一份(通常通过 COMDAT 节去重),但编译阶段仍需多次实例化,拖慢编译速度(这句话来源于deepseek)。
代码编译慢
如果你的项目编译起来比较慢,甚至卡顿,那么原因大概率是因为使用了模板对象和模板函数,而且跟多地方实例化了模板对象或者模板函数。
编译期生成代码
模板不是运行时机制:每次使用不同的模板参数(如
std::vector<int>
和std::vector<float>
),编译器会在编译时生成一份独立的代码(实例化)。重复实例化:同一个模板在多个编译单元(
.cpp
文件)中被不同参数实例化时,每个文件都会生成一次代码,导致冗余工作。
重复实例化:同一个模板在多个编译单元(.cpp 文件)中被不同参数实例化时,每个文件都会生成一次代码,导致冗余工作。
如果多一个编译单元中使用相同的参数实例化,是只会生成一个实例化对象,还是实例化出多个对象?
在 C++ 中,如果同一个模板在多个编译单元(.cpp
文件)中以相同的参数实例化,默认情况下每个编译单元都会独立生成一份实例化代码,导致冗余。
如何避免重复实例化
显式实例化(Explicit Instantiation)
在一个单独的编译单元中显式实例化模板,其他文件通过 extern
声明引用它:
// vector_int.cpp(显式实例化)
#include <vector>
template class std::vector<int>; // 显式实例化
// a.cpp(其他文件声明外部实例)
#include <vector>
extern template class std::vector<int>; // 声明不实例化
void foo() { std::vector<int> v; }
// b.cpp
#include <vector>
extern template class std::vector<int>; // 同上
void bar() { std::vector<int> v; }
效果:
std::vector<int>
仅在vector_int.cpp
中实例化一次。链接时所有文件共享同一份代码。
优点:显著减少编译时间和目标文件大小。
这种方式来源于deepseek,未验证。