为什么声明/定义必须都在C++模板类的源文件中?
源文件彼此独立编译为可执行代码,然后再链接到主程序。另一方面,模板函数不能在没有模板参数的情况下编译。因此,使用它们的文件需要有该代码才能编译。因此这些函数需要在头文件中可见。
应许例如:
template<class T>
void swap(T & a, T & b)
{
T temp = a;
a = b;
b = temp;
}
T类这里的唯一的要求是,它有一个公共的赋值运算符(=)。这就是所有曾经实施或设想过的课程。但是,每个类都以自己的方式实现赋值运算符。不能为交换生成相同的机器代码<int>,交换<双重>和交换<字符串>。这些功能中的每一个都必须是唯一的。同时,编译器不可能预见到可能传递给该函数的所有不同类型,因此它不能提前生成函数。所以它必须等到函数被调用,然后它才能被编译。
例如,假设我具有上面定义在“swap.h”中的那个函数。然后在“main.cpp”中,我这样做:
int main()
{
int a=5, b=10;
double c=3.5, d=7.9;
string s1="hello";
string s2="world";
swap(a,b);
swap(c,d);
swap(s1,s2);
}
在此示例中,创建了3个不同的函数。一个交换ints,一个交换双打,一个交换字符串。为了创建这些函数,编译器需要能够看到模板代码。如果它是在一个单独的源文件中,例如“swap.cpp”,编译器将无法看到它,因为就像我之前所说的那样,每个源文件都是相互独立编译的。
你问为什么模板体必须在头文件?这是因为编译器需要同时知道主体和模板参数以生成机器代码。模板参数在使用模板(实例化)的位置是已知的。这给你一个平凡的例子和两个非平凡的例子:
- (Trivial)该模板只在一个源文件中使用,所以正文可以在同一个源文件中。
- 使身体在每次使用时都可用,这通常意味着在头文件中。
- 在包含正文的源文件中,显式实例化每个需要的模板参数组合。
你的问题的简短答案是没有义务声明和定义模板类在同一个源文件中。
事实上,我认为这是一件坏事,但它是完全可以理解的,因为分开使用它们非常困难(但它可以完成!)。
编辑
假设你有
- myTemplateClass。为h,它声明了一个模板类MyTemplateClass
- myTemplateClass.hpp定义其类成员(包括myTemplateClass.h)
- 使用MyTemplateClass的内部的main.cpp
只需包括在myTemplateClass.h main.cpp中和创建myTemplateClassInt.cpp如下:
#include "myTemplateClass.hpp"
template MyTemplateClass<int>;
这样做,你告诉编译器实例MyTemplateClass的模板参数“INT”的所有模板方法。由于它可以访问myTemplateClass.hpp,所以这些方法将被完美地生成......并且链接器不会发生抱怨。
当然,这种方法要求您使用一些地方定义您的模板类的实例化版本。
-----------如何? – lurscher 2011-07-12 18:31:51
@lurscher:查看我的答案的编辑版本。 – 2011-07-13 07:51:00
我刚刚意识到我没有真正回答你的问题。但那只是因为你说错了。我知道你的意思,因为我记得曾经有过同样的问题,所以我对这个问题很熟悉。问题应该是“为什么声明/定义必须都在C++模板类的头文件中”?不幸的是,我没有编辑问题的代表。 – 2010-10-15 07:58:56
因此,在我的问题中'source'应该改为'header',对吧? – tem 2010-10-15 08:02:37
是的。在C++中,源文件是包含函数体(.cpp)的文件。标题是包含你的原型和你的类体(.h或.hpp)的标题。 – 2010-10-15 08:16:23