关于C ++模板和显式声明

时间:2011-08-20 20:53:45

标签: c++ c++11

我只花了大约20分钟试图找出为什么我的一些模板方法通过编译而不是链接。

原来我需要明确声明我的模板方法。

这是一种类似的东西:

class Test {
   template<class Source> void Save(Source& obj);
};

然后我会在某处使用它:

Test t;
ClassDerivedFromInterface obj;
t.Save(obj);

它编译得很好但没有链接。直到我补充:

template void Test::Save(ClassDerivedFromInterface);

我想了解在哪种情况下需要明确声明。

由于

4 个答案:

答案 0 :(得分:5)

简而言之,您需要让实例化模板的翻译单元可以看到模板函数的整个主体( definition )。因此,当您说t.Save(obj);时,该翻译单元应该可以访问Save的定义。通常,您可以通过在头文件本身中包含函数模板的定义来实现此目的。

原因是模板不是普通的编译代码,以后可以随意链接。相反,模板是一个代码生成工具,可以按需生成必要的代码 - 如果愿意,可以自动复制/粘贴,然后搜索和替换。

因此,在您编写该行之前,函数Save(ClassDerivedFromInterface&)的实际可编译代码不会存在。如果只显示函数模板的声明,那么模板只生成具体函数的声明,但不生成它的正文,因此在链接时你会注意到函数丢失了。

总结一下,模板本身无法编译,只有它们的具体实例可以,并且您必须注意确保在实例化时具体实例始终可用。显式实例化,因为它有效并允许您将一些特定实例打包到一个单独的TU中,但通常难以维护且不可伸缩,并且当您让编译器隐式实例化时,您可以避免显式实例化的其他缺点。因此,通常最好将整个定义打包到头文件中。

答案 1 :(得分:2)

如果在编译时看不到模板源,则需要显式声明模板。这个链接非常好,也是一个很棒的网站:

C++ FAQ 35.13

答案 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)

编译器需要知道您将在模板中使用哪些类型。如果您创建模板类,然后将其与intchardouble一起使用,则编译器将为这些类型的模板创建方法。如果在使用它的单独编译单元中编译模板方法,编译器将不会为您需要的类型实例化模板。但是,如果您明确地实例化模板,编译器将创建您告诉它的任何内容。