我理解模板的概念,以及为什么我们需要在头文件中定义模板成员函数。另一个选项是在cpp文件中定义模板函数,并显式实例化模板类,如下所示。
模板.h
#include <iostream>
using namespace std;
template <typename T> class myclass
{
public:
void doSomeThing();
};
template.cpp
#include <iostream>
#include "template.h"
using namespace std;
template <typename T> void myclass<T>::doSomeThing()
{
cout << "in DoSomething" << endl;
}
template class myclass <int>; // Why we shouldn't use template<> class myclass <int> here?
main.cpp
#include <iostream>
#include "template.h"
using namespace std;
int main()
{
myclass<int> obj;
obj.doSomeThing();
}
我在Ubuntu操作系统上使用g++ main.cpp template.cpp
进行编译,并且我能够调用doSomeThing()
我有几个问题如下。
- 如果我们需要显式实例化类模板,它应该是
template <> class myclass <int>
但是当我在template.cpp而不是template class myclass <int>
,它是抛出对"myclass::doSomeThing(("的未定义引用错误。为什么在这种情况下我们不应该使用<>
我尝试将myclass(对于int(的一个对象实例化为
myclass <int> obj;
,而不是中的template <> class myclass <int>;
template.cpp,如下所示。#include <iostream> #include "template.h" using namespace std; template <typename T> void myclass<T>::doSomeThing() { cout << "in DoSomething" << endl; } myclass <int> obj;
我认为template.cpp既有通过template.h的模板声明,也有template.cpp中的所有模板函数定义,所以为int类型创建对象将为int创建类,它将包含int类型的函数定义。因此,当g++编译main.cpp时,它拥有int类型的所有函数,如果我先编译template.cpp,然后将main.cpp编译为
g++ template.cpp main.cpp
,则为myclass创建对象(针对int数据类型(将起作用。但这也引发了main.cpp:(.text+0x1f(:对"myclass::doSomeThing(("的未定义引用错误。我不明白为什么这是投掷错误。有人能帮助我理解为什么这不起作用吗。
- 如果我们需要显式实例化类模板,它应该是
template <> class myclass <int>
不,不应该。这不是用于显式实例化的语法。(这是模板专业化的语法。(
为什么我们不应该在这种情况下使用
<>
?
因为这不是显式实例化的语法。正确的语法是:
template class|struct template-name < argument-list > ;
- 我无法理解为什么这是抛出错误
因为模板没有明确的实例化定义。如果没有显式实例化,模板可能不会在尚未定义模板的TU中使用。
您的第一个问题是为什么要写:
template<> class myclass <int>;
导致未定义的引用错误。答案是template<>
声明了一个显式专门化:这意味着myclass<int>::doSomething
有一个特殊的定义,它取代了文件早期的通用定义。但是,没有提供专门化的定义。因此,当template.cpp
被翻译时,不发出myclass<int>::doSomething
的定义。
你的第二个问题是为什么用替换显式实例化
myclass <int> obj;
则CCD_ 15中的CCD_。答案是双重的:
当编译器在翻译
template.cpp
时隐式实例化myclass<int>
时,它不会隐式实例化myclass<int>::doSomething
,因为此时还不需要函数的定义。即使编译器在
template.cpp
的翻译期间隐式实例化myclass<int>::doSomething
,也不能保证该隐式实例化使该实例化的定义可用于其他翻译单元。(实际上,编译器可以通过内部链接生成它。(
参见C++17[温度]/7
函数模板、类模板的成员函数、变量模板或类模板应在隐式实例化的每个翻译单元中定义(17.7.1(,除非在某个翻译单元中显式实例化(17.7.2(相应的专门化;没有诊断必需。
这意味着,如果您需要从翻译第一单元调用函数模板,但您只想在翻译第二单元中定义该函数模板,则翻译第二单元必须使用所需参数显式实例化函数模板。隐式实例化不算数。
(注意,myclass<int>
的显式实例化也将隐式实例化myclass<int>
的所有成员函数的定义。(