我正在尝试使用专门的析构函数。这段代码完全有效,编译得很好:
#include <iostream>
using namespace std;
template <typename T>
class Cat
{
public:
~Cat();
};
template <typename T>
Cat<T>::~Cat()
{
std::cout << "T" << std::endl;
}
template <>
Cat<int>::~Cat()
{
std::cout << "int" << std::endl;
}
int main()
{
Cat<int> c1;
Cat<float> c2;
return 0;
}
但是,如果我将类和析构函数放在单独的文件“Cat.h”中并在Main.cpp中执行#include "Cat.h"
,我会收到链接器错误:LNK2005 "public: __thiscall Cat<int>::~Cat<int>(void)" (??1?$Cat@H@@QAE@XZ) already defined in Cat.obj
。为什么呢?
答案 0 :(得分:3)
听起来你有以下几点:
template <>
Cat<int>::~Cat()
{
std::cout << "int" << std::endl;
}
在两个翻译单元中包含的头文件中。函数模板的显式特化是非内联函数(C ++ 14 [temp.expl.spec] / 12);所以这是ODR违规。
如果您在同一个地方实现了非模板成员函数(或自由函数),则会出现同样的错误:两个翻译单元最终都会得到该函数的副本,即使该函数也是如此两份是完全相同的。
要解决此问题,请将关键字inline
放在template<>
之前。
在评论中有一些关于为类模板的成员函数提供显式特化的合法性的讨论。我认为这是正确的,根据C ++ 14 [temp.expl.spec] / 6:
的限制如果一个模板,一个成员模板或一个类模板的成员被明确地专门化,那么该特化应该在第一次使用该特化之前声明,这将导致隐式实例化发生,在每个翻译单元中使用发生;无需诊断。如果程序没有提供显式特化的定义,并且特殊化的使用方式会导致隐式实例化或成员是虚拟成员函数, 程序格式错误,无需诊断。
另外,第7节:
为函数模板,类模板,变量模板,类模板的成员函数,类模板的静态数据成员,类模板的成员类,类模板的成员枚举,类模板的成员类模板放置显式特化声明,类模板的成员函数模板,类模板的静态数据成员模板,类模板成员模板的成员函数,非模板类成员模板的成员函数,非模板类的静态数据成员模板,成员函数模板类模板的成员类等,以及类模板的部分特化声明的放置,变量模板,非模板类的成员类模板,非模板类的静态数据成员模板,类模板的成员类模板等可以根据显式spe的相对位置来影响程序是否格式正确上文和下文所述的翻译单元中的cialization声明及其实例化点。在写专业时,要小心它 地点;或者使它编译将是一个试图点燃其自焚的试验。
在你的程序中,它位于完美的位置:紧跟在课程定义之后。如果在至少遇到专业化的声明之前可能已经实例化了类,则会出现危险的注意事项。
答案 1 :(得分:1)
您的Cat.cpp
和main.cpp
翻译单元都可能包含相同的Cat.h
标头文件。将整个模板类放在头文件中,删除Cat.cpp
翻译单元并在没有它的情况下进行编译
Live example
此SO帖子中的更多细节:
Why can templates only be implemented in the header file?