我正在使用模板来实现CRTP模式。使用下面的代码,我得到链接器错误(对于基类CPConnectionBase
中定义的所有方法),如下所示:
错误LNK2001:未解析的外部符号“public:void __thiscall CPConnectionBase :: start(void)”(?start @?$ CPConnectionBase @ VTNCPConnection @@@@ QAEXXZ)
我想这里的解决方案是显式模板实例化。事实上,当我添加
时,我可以构建我的代码#include "TNCPConnection.h"
template class CPConnectionBase<TNCPConnection>;
到CPConnectionBase.cpp文件。这肯定是错误的地方,因为我不想将所有可能的派生类的头部包含到基类的源代码中(我可能也希望在另一个项目中使用基类与其他派生类)。
所以我的目标是在派生类(TNCPConnection.h或TNCPConnection.cpp)的源文件中实例化模板,但我找不到解决方案。添加
template class CPConnectionBase<TNCPConnection>;
到文件TNCPConnection.cpp没有解决我的链接器问题,并添加
template<> class CPConnectionBase<TNCPConnection>;
到文件TNCPConnection.cpp给出了编译时错误:
错误C2908:显式专业化; 'CPConnectionBase'已经实例化
如何在不依赖派生类的头文件的基类实现的情况下摆脱链接器错误?
这是我的代码的骨架:
template <class Derived>
class CPConnectionBase : public boost::enable_shared_from_this<Derived>
{
public:
void start();
};
#include "stdafx.h"
#include "CPConnectionBase.h"
template<class Derived>
void CPConnectionBase<Derived>::start()
{
...
}
#include "CPConnectionBase.h"
class TNCPConnection : public CPConnectionBase<TNCPConnection>
{
public:
void foo(void);
};
#include "stdafx.h"
#include "TNCPConnection.h"
void TNCPConnection::foo(void)
{
...
}
答案 0 :(得分:3)
CPConnectionBase::start()
的定义必须在您显式实例化该类的位置可用 - 否则该函数将不会被实例化,并且此非实例化将以静默方式发生(跟随链接器错误)。
标准解决方案是标题CPConnectionBase.hpp
,它定义了CPConnectionBase.h
中声明的模板函数。在CPConnectionBase.hpp
中加入TNCPConnection.cpp
并在那里明确实例化。
答案 1 :(得分:2)
我应该在这里添加一个注释: MSVC允许在成员函数之前在同一编译单元内声明显式特化。 GCC(4.7)要求它们位于文件的末尾。 即。
MSVC:
template class TClass<Base>;
template <class T> void TClass<T>::Function() {}
template <class T> void TClass<T>::Function() {}
template class TClass<Base>;
答案 2 :(得分:1)
首先,我建议将CPConnectionBase.cpp
重命名为CPConnectionBase.inl
,因为它不包含任何非模板代码。
在您实例化模板时,您需要先#include <CPConnectionBase.inl>
。我建议在TNCPConnection.cpp
中进行。
或者,您可以将CPConnectionBase
实现移动到CPConnectionBase.h
头文件,编译器将自动处理实例化。
答案 3 :(得分:0)
将模板化代码从.cpp移动到标题。
当您在模板中包含标题时,模板化代码将根据它在标题中找到的内容在目标代码中生成。
如果代码在.cpp文件中,则无法找到它,因此无法生成(因为您只包含.h)
答案 4 :(得分:0)
您还可以使用“分离模型”。只需在一个文件中定义模板,然后标记即可 关键字 export :
的定义export template <class Derived>
class CPConnectionBase : public boost::enable_shared_from_this<Derived>
{
public:
void start();
};