2009-08-30 119 views
24

我在调用模板类时遇到了问题。 我声明了一个新的类型名称Array,它是一个模板;C++模板,链接错误

在.HPP文件:

template <typename T> 
class Array 
{ 
public: 
    Array(); 
}; 

在.cpp文件:

template <typename T> 
Array<T>::Array() 
{ 
//Do something 
} 

在主:

Array<int> arr; 

我得到链接错误:无法解析的外部符号的构造函数。

任何想法?

+0

将这个问题链接到https://stackoverflow.com/questions/495021/why-can-templates-only-be-implemented-in-the-header-file是有用的,但它不是真的重复。 OP不知道在这个问题上完全假设的东西。 – Winter 2017-06-22 15:58:33

回答

47

模板功能,包括成员函数,必须在头文件中编写的。这意味着如果你有一个模板类,它的实现必须完全在头部。这是因为编译器需要访问整个模板定义(而不仅仅是签名)才能为模板的每个实例化生成代码。

+0

是的,它的工作。 你可以添加更多解释为什么你需要在头文件中定义所有的解释吗?另外我添加的实现我在“endif”之前添加了所有,对吧? – 2009-08-30 14:24:29

+1

正确。有关为什么的一个很好的解释,请参阅http://www.parashift.com/c++-faq-lite/templates.html#faq-35.12和以下与月亮阴影相关的问题35.13。 – 2009-08-30 14:29:00

+7

从技术上讲,这不是一个要求。您可以在某个编译单元中明确实例化该模板,并在其他地方使用该模板,但这需要相当多的手动内务管理(为项目中使用的每种新类型添加显式实例),甚至可能导致不可能(如果必须的话与尚未知的类型一起工作)。 – 2009-08-30 19:48:54

8

把这两样模板声明和模板函数在头文件 定义。大多数C++编译器不轻松支持单独的编译模型模板,

3

你有这里的问题是,你藏在.cpp文件中构造函数的定义。这个定义适用于所有类型T,包括T如您使用int,但实际上,因为它仍然只是一个声明,任何不提供的定义。
链接器找不到符号Array<int>::Array()。现在

,您可以添加这样一行:

Array<int> arr1; 

您Array.cpp文件的末尾,这使得编译器实例化的正确定义了链接所期待的。然而,这仅仅提供一个定义,的Array<int>并没有其他。

该解决方案将工作,直到你需要不同的模板参数的Array,说:double,在这一点上,你将需要添加:

Array<double> arr2; 

您Array.cpp文件的末尾 - 现在你可以看到这是不可持续的!

如果您需要C++与任何类型一起使用,您可能需要将来,现在是将ctor的定义(以及大概所有其他成员函数)向上移动到标题(和删除.cpp文件,因为它不会留下任何东西)。

0

如上所述,在C++模板中,新方法的过程由编译器在编译时执行,问题是它需要在此期间知道thm的所有定义,因此所有的类/函数声明都必须是ar h或hpp文件。

1

另一个答案,编译只是你的.cpp文件(不是主),并检查目标文件的大小,然后创建一个empty.cpp文件,然后编译empty.cpp。最后比较两个对象文件的大小。你会看到它们具有相同的大小,这意味着你的.cpp文件不需要编译,所以链接器找不到任何东西。