通常,当我创建一个类时,我会为该类创建一个标头和一个源.我听说过使用模板类,你必须将函数实现放在头文件中.我试过两种方式,并从第一种方式得到编译错误.第二种方式很好.但是,我喜欢将代码组织到头文件和源文件中,那么是否可以将函数实现放入源文件中?(也许它需要特殊的编译标志或语法?)或者我应该将em保留在标题中?
谢谢!
And*_*son 15
通常,所有模板代码必须位于头文件中,因为编译器需要在实例化时知道完整类型.
正如Aaron在下面所说,可以将实现细节放在.cpp-file中,在特定情况下,您事先知道模板将被实例化的所有可能类型,并使用这些类型显式实例化它.如果模板在代码中的某个位置使用其他类型进行实例化,则会出现链接器错误.
至少在视觉上将接口与实现分开的一个非常普遍的通用解决方案是将所有实现放在.inc(.tcc或.ipp)文件中,并将其包含在头文件的末尾.
请注意,将模板类成员放在类定义之外的语法(无论是使用特定解决方案还是常规解决方案)都有点麻烦.你需要写:
// in test.h
template <class A>
class Test
{
public:
void testFunction();
};
#include "test.inc"
// in test.inc
template <class A>
void Test<A>::testFunction()
{
// do something
}
Run Code Online (Sandbox Code Playgroud)
Aar*_*aid 14
(编辑:这是一个稍微强大的版本,它允许将实现编译成一个单独的.o文件.模板应该在实现cpp文件的末尾显式实例化.也许这只是g ++的一个问题.)
如果您知道将实例化哪些模板并且可以在标头实现文件中列出它们,则无需将实现放在标头中.例如,如果您知道只使用int和std::string,则可以将其放在头文件中:
// test.h
template <class A>
class Test
{
public:
void f();
};
Run Code Online (Sandbox Code Playgroud)
并将f()的实现放入一个普通的test.cpp文件中:
// test.cpp
#include "test.h"
template <class A> void Test<A>::f() {
// implementation
}
template class Test<int>;
template class Test<string>;
Run Code Online (Sandbox Code Playgroud)
最后两行显式实例化模板类.在看到成员函数的实现之后,最好将它放在实现文件的末尾.然后,您可以将其编译为.o文件g++ -c test.cpp.这test.o文件将包含两个完整的实现Test<int>,并Test<string>可以在不应用程序中的其余任何困难联系起来.
它有效,但这是一个好主意吗?这取决于背景.在许多情况下,这非常有效.如果您正在为项目中的"内部"使用编写模板,那么您将知道将实例化哪些模板,哪些模板不会实例化.但是相反,如果你正在做向公众提供一些东西,必须是非常灵活的,那么你将需要在头文件的实现.
提示:即使是供公众使用,也请查看方法,看看是否有任何方法的参数和返回类型与模板参数无关.如果是这样,您可以将它们作为(纯)虚函数放入Base类.这个Base类不使用任何模板,因此您可以Base*在大部分应用程序中使用它(template <class A> class Test : public Base { ...允许您在整个应用程序中限制模板化代码的范围.我发现这在最近的大部分基础行为时很有用并且类的构造取决于模板参数,但是已经构造的对象的接口不依赖于模板参数.
回答原始问题:不,[成员]函数模板的定义不必进入标题.但是,编译器需要查看定义以实例化模板.对于使用许多不同类型实例化的模板,您希望模板在使用时隐式实例化.例如,对于类模板std::vector<...>和类似于函数模板的情况std::copy(...).在这种情况下,将模板定义与其声明分开几乎肯定是不切实际的,尽管我个人将定义放在头文件底部的单独文件中.
对于仅使用几种类型(例如流类)实例化的模板,或者std::basic_string<...>通常更好的是在单独的类似头文件中定义函数模板,该文件仅包含在显式实例化它们的实现文件中.这样,实例化模板的工作仅花费一次而不是在使用它的每个翻译单元中.特别是对于流类,这产生了巨大的差异(主要用于编译和链接时间,但在某些系统上也用于可执行大小)....我敢肯定,几乎没有人已经使用流类不同的字符类型比的麻烦char和wchar_t(提示:这是不平凡的,为各个方面安排来实现存在于中std::locale).如果只有一组有限的类型可以使用模板,那么显式实例化模板的技术也可以很好地工作.