如何正确进行显式模板实例化?

时间:2012-02-01 10:18:22

标签: c++ templates visual-c++ linker

我正在使用模板来实现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'已经实例化

如何在不依赖派生类的头文件的基类实现的情况下摆脱链接器错误?

这是我的代码的骨架:

CPConnectionBase.h

template <class Derived>
class CPConnectionBase : public boost::enable_shared_from_this<Derived>
{
public:
    void start();
};

CPConnectionBase.cpp

#include "stdafx.h"
#include "CPConnectionBase.h"

template<class Derived>
void CPConnectionBase<Derived>::start()
{
    ...
}

TNCPConnection.h

#include "CPConnectionBase.h"

class TNCPConnection : public CPConnectionBase<TNCPConnection>
{
public:
    void foo(void);
};

TNCPConnection.cpp

#include "stdafx.h"
#include "TNCPConnection.h"

void TNCPConnection::foo(void)
{
    ...
}

5 个答案:

答案 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();
};