关于c++模板和显式声明
About C++ template and explicit declaration
我刚刚花了大约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
模板声明可以被模板用户访问,所以你不需要显式的声明。
编译器需要知道你将在模板中使用什么类型。如果您创建一个模板类,然后使用它,例如int
、char
和double
,那么编译器将为这些类型的模板创建方法。如果在与使用模板方法的地方不同的编译单元中编译模板方法,则编译器将不会为所需的类型实例化模板。但是如果你显式地实例化模板,编译器会创建你要它创建的任何东西。
- .cpp和.h文件中的模板专用化声明
- 未在作用域中声明unordered_map
- C++避免重复声明的语法是什么
- 如何确保C++函数在定义之前声明(如override关键字)
- 错误:未在此范围内声明'reverse'
- 奇怪的(对我来说)返回声明 - 在谷歌上找不到任何关于它的信息
- 为什么在定义函数之前先声明它
- 如何声明特征矩阵,然后通过嵌套循环初始化它
- #ifdef和未声明的标识符
- 没有显式声明的int[]中的foreach
- 在基于范围的for循环中使用结构化绑定声明
- 在将变量声明为引用时,堆在释放后使用
- C++:无法访问声明的受保护成员
- 为什么我不能在一个类的不同行中声明和定义成员变量?
- 我不明白为什么我声明一个空的内部结构并将其传递给构造函数
- 使用cmake从源代码构建MySQL连接器/C++失败(与以前的声明冲突)
- 在函数内部的声明中初始化数组,并在外部使用它
- Visual Studio中的函数声明和函数定义问题
- c++类声明时,相同的例程,不同的成员变量类型
- 在 .h 文件中的类中声明静态变量和在.cpp文件中声明"global"变量有什么区别