我只花了大约 20 分钟试图弄清楚为什么我的一些模板方法通过了编译但没有链接。
原来我需要显式声明我的模板方法。
是这样的:
class Test {
template<class Source> void Save(Source& obj);
};
然后我会在某个地方像这样使用它:
Test t;
ClassDerivedFromInterface obj;
t.Save(obj);
它编译正常但没有链接。直到我添加:
template void Test::Save(ClassDerivedFromInterface);
我想了解在什么情况下需要明确声明。
谢谢
最佳答案
简而言之,您需要让模板函数的整个主体(定义)对实例化模板的翻译单元可见。因此,当您说 t.Save(obj);
时,该翻译单元应该可以访问 Save
的定义。通常,您通过在头文件本身中包含函数模板的定义来实现这一点。
这样做的原因是模板不是普通的代码,可以编译后可以随意链接。相反,模板是一种代码生成工具,可以根据需要生成必要的代码 - 复制/粘贴的自动版本,然后是搜索和替换,如果您愿意的话。
因此,您的函数 Save(ClassDerivedFromInterface&)
的实际可编译代码在您编写该行之前不会存在。如果只有函数模板的声明是可见的,那么模板只生成具体函数的声明,而不是函数体,因此在链接时您会注意到函数丢失了。
总而言之,模板本身是不能被编译的,只有它们的具体实例可以,而且你在实例化它们时必须注意确保具体实例始终可用。您拥有的显式实例化可以工作,并允许您将一些特定实例打包到一个单独的 TU 中,但通常这很难维护且不可扩展,并且当您让编译器隐式实例化时,您可以避免显式实例化的其他缺点。所以通常最好将您的整个定义打包到头文件中。
关于c++ - 关于 C++ 模板和显式声明,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7134617/