我只花了大约20分钟试图找出为什么我的一些模板方法通过编译而不是链接。
原来我需要明确声明我的模板方法。
这是一种类似的东西:
class Test {
template<class Source> void Save(Source& obj);
};
然后我会在某处使用它:
Test t;
ClassDerivedFromInterface obj;
t.Save(obj);
它编译得很好但没有链接。直到我补充:
template void Test::Save(ClassDerivedFromInterface);
我想了解在哪种情况下需要明确声明。
由于
答案 0 :(得分:5)
简而言之,您需要让实例化模板的翻译单元可以看到模板函数的整个主体( definition )。因此,当您说t.Save(obj);
时,该翻译单元应该可以访问Save
的定义。通常,您可以通过在头文件本身中包含函数模板的定义来实现此目的。
原因是模板不是普通的编译代码,以后可以随意链接。相反,模板是一个代码生成工具,可以按需生成必要的代码 - 如果愿意,可以自动复制/粘贴,然后搜索和替换。
因此,在您编写该行之前,函数Save(ClassDerivedFromInterface&)
的实际可编译代码不会存在。如果只显示函数模板的声明,那么模板只生成具体函数的声明,但不生成它的正文,因此在链接时你会注意到函数丢失了。
总结一下,模板本身无法编译,只有它们的具体实例可以,并且您必须注意确保在实例化时具体实例始终可用。显式实例化,因为它有效并允许您将一些特定实例打包到一个单独的TU中,但通常难以维护且不可伸缩,并且当您让编译器隐式实例化时,您可以避免显式实例化的其他缺点。因此,通常最好将整个定义打包到头文件中。
答案 1 :(得分:2)
如果在编译时看不到模板源,则需要显式声明模板。这个链接非常好,也是一个很棒的网站:
答案 2 :(得分:2)
当您的模板定义无法从使用它们的代码中访问时,您需要显式声明,请考虑以下事项:
template.h - template declarations
template.cpp - template definitions
main.cpp - template usage
template.cpp
未包含在main.cpp
中,因此模板用户无法访问,因此您需要明确声明。
但如果您的结构是:
template.h - template declarations and definitions
main.cpp - template usage
模板用户可以访问模板声明,因此您不需要显式声明。
答案 3 :(得分:1)
编译器需要知道您将在模板中使用哪些类型。如果您创建模板类,然后将其与int
,char
和double
一起使用,则编译器将为这些类型的模板创建方法。如果在使用它的单独编译单元中编译模板方法,编译器将不会为您需要的类型实例化模板。但是,如果您明确地实例化模板,编译器将创建您告诉它的任何内容。