Do template class member function implementations always have to go in the header file in C++?
通常,当我创建一个类时,我会为该类创建一个头和一个源。我听说,对于模板类,必须将函数实现放在头中。我尝试了两种方法,第一种方法是编译错误。第二种方法很管用。但是,我喜欢将代码组织到头文件和源文件中,所以是否可以将函数实现放入源文件中?(可能需要特殊的编译标志或语法?)或者我应该把它们放在头上吗?
谢谢!
通常,所有模板代码都必须在头文件中,因为编译器需要知道实例化点的完整类型。
正如Aaron在下面所说,在特定情况下,可以将实现细节放在
对于至少在视觉上与实现分离的接口,一个非常常见的一般解决方案是将所有实现放在一个
请注意,将模板类成员放在类定义之外的语法(无论是使用特定的解决方案还是常规的解决方案)有点麻烦。你需要写:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | // 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 } |
(已编辑:这是一个略为强大的版本,允许将实现编译成单独的.o文件。模板应该在实现cpp文件的末尾显式实例化。也许这只是G++的问题。)
如果您知道将实例化哪些模板,并且可以将它们列在header->strike>implementation文件中,则不需要将实现放在头中。例如,如果您知道只使用
1 2 3 4 5 6 7 | // test.h template <class A> class Test { public: void f(); }; |
并将f()的实现放入普通test.cpp文件中:
1 2 3 4 5 6 7 | // test.cpp #include"test.h" template <class A> void Test<A>::f() { // implementation } template class Test<int>; template class Test<string>; |
最后两行显式地实例化模板类。在看到成员函数的实现之后,最好将它放在实现文件的末尾。然后您可以将它编译成.o文件
这是可行的,但这是个好主意吗?这取决于上下文。在许多情况下,这是非常有效的。如果您正在为项目中的"内部"使用编写模板,那么您知道哪些模板将被实例化,而哪些模板将不被实例化。但是,如果您将一些必须非常灵活的东西提供给公众,那么您将需要在头文件中包含实现。
提示:即使是用于公共消费,也要查看这些方法,看看是否有任何方法的参数和返回类型与模板参数无关。如果是这样,您可以将它们作为(纯)虚拟函数放到基类中。这个基类不使用任何模板,因此您可以在大部分应用程序(
要回答最初的问题:不,不必将[成员]函数模板的定义放在头中。但是,编译器需要查看定义来实例化模板。对于用许多不同类型实例化的模板,您希望在使用模板时将其隐式实例化。例如,对于类模板(如EDOCX1)(0)和函数模板(如EDOCX1)(1))。在这种情况下,将模板定义从声明中分离出来几乎肯定是不切实际的,尽管我个人将这些定义放在包含在头文件底部的单独文件中。
对于仅使用流类或
虽然从技术上讲,您可以将实现与接口分离,但模板的语法对于重复键入非常烦人,我强烈建议您先别着急,然后将实现放在类中,直到消除异味。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | template <class X> class klass_t { public: void f(); void g(); void h(); }; template <class X> void klass_t<X>::f() { ... } template <class X> void klass_t<X>::g() { ... } template <class X> void klasS_t<X>::h() { ... } |
本来应该是:
1 2 3 4 5 6 7 | template <class X> class klass_t { public: void f() { ... } void g() { ... } void h() { ... } }; |
现在假设您想要添加另一个模板参数(如下所示)。现在您必须在n个位置更改模板参数列表,而不仅仅是一个。
1 2 3 4 5 6 7 | template <class X, class Y> class klass_t { public: void f(); void g(); void h(); }; |
除非你有充分的理由不这么做,否则把所有的东西都放到课堂上就容易多了。
模板实现需要在编译时知道。这意味着编译器必须能够看到这些实现。没有办法解决这个问题。
如果您想对实现细节保密,就没有办法做到这一点。当然,您可以混淆您的代码,但这并不是什么障碍。
如果您唯一关心的是代码组织,那么可以用实现创建一个单独的include文件,并将其包含在主标题的末尾(就像andreas的建议一样)。