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

About C++ template and explicit declaration

本文关键字:声明 c++ 关于      更新时间:2023-10-16

我刚刚花了大约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++ FAQ 35.13

当使用模板定义的代码无法访问模板定义时,您需要显式声明,请考虑以下事项:

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

模板声明可以被模板用户访问,所以你不需要显式的声明。

编译器需要知道你将在模板中使用什么类型。如果您创建一个模板类,然后使用它,例如intchardouble,那么编译器将为这些类型的模板创建方法。如果在与使用模板方法的地方不同的编译单元中编译模板方法,则编译器将不会为所需的类型实例化模板。但是如果你显式地实例化模板,编译器会创建你要它创建的任何东西。