即使我正在.cpp文件中实例化一个伪对象,.cpp文件内模板函数的定义也不起作用



我理解模板的概念,以及为什么我们需要在头文件中定义模板成员函数。另一个选项是在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()

我有几个问题如下。

  1. 如果我们需要显式实例化类模板,它应该是template <> class myclass <int>但是当我在template.cpp而不是template class myclass <int>,它是抛出对"myclass::doSomeThing(("的未定义引用错误。为什么在这种情况下我们不应该使用<>
  2. 我尝试将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(("的未定义引用错误。我不明白为什么这是投掷错误。有人能帮助我理解为什么这不起作用吗。

  1. 如果我们需要显式实例化类模板,它应该是template <> class myclass <int>

不,不应该。这不是用于显式实例化的语法。(这是模板专业化的语法。(

为什么我们不应该在这种情况下使用<>

因为这不是显式实例化的语法。正确的语法是:

template class|struct template-name < argument-list > ;

  1. 我无法理解为什么这是抛出错误

因为模板没有明确的实例化定义。如果没有显式实例化,模板可能不会在尚未定义模板的TU中使用。

您的第一个问题是为什么要写:

template<> class myclass <int>;

导致未定义的引用错误。答案是template<>声明了一个显式专门化:这意味着myclass<int>::doSomething有一个特殊的定义,它取代了文件早期的通用定义。但是,没有提供专门化的定义。因此,当template.cpp被翻译时,不发出myclass<int>::doSomething的定义。

你的第二个问题是为什么用替换显式实例化

myclass <int> obj;

则CCD_ 15中的CCD_。答案是双重的:

  1. 当编译器在翻译template.cpp时隐式实例化myclass<int>时,它不会隐式实例化myclass<int>::doSomething,因为此时还不需要函数的定义。

  2. 即使编译器在template.cpp的翻译期间隐式实例化myclass<int>::doSomething,也不能保证该隐式实例化使该实例化的定义可用于其他翻译单元。(实际上,编译器可以通过内部链接生成它。(

参见C++17[温度]/7

函数模板、类模板的成员函数、变量模板或类模板应在隐式实例化的每个翻译单元中定义(17.7.1(,除非在某个翻译单元中显式实例化(17.7.2(相应的专门化;没有诊断必需。

这意味着,如果您需要从翻译第一单元调用函数模板,但您只想在翻译第二单元中定义该函数模板,则翻译第二单元必须使用所需参数显式实例化函数模板。隐式实例化不算数。

(注意,myclass<int>的显式实例化也将隐式实例化myclass<int>的所有成员函数的定义。(

最新更新