I’m using templates for implementing the CRTP pattern. With the code below I’m getting linker errors (for all the methods that are defined in the base class CPConnectionBase) like this:
error LNK2001: unresolved external symbol “public: void __thiscall CPConnectionBase::start(void)” (?start@?$CPConnectionBase@VTNCPConnection@@@@QAEXXZ)
I guess the solution here is explicit template instantiation. And indeed I can build my code when I add
#include "TNCPConnection.h"
template class CPConnectionBase<TNCPConnection>;
to the file CPConnectionBase.cpp. This is certainly the wrong place since I don’t want to include the header of all possible derived classes into the source of the base class (I might want to use the base class also in another project with other derived classes).
So my goal is to instantiate the template in the source file of the derived class (TNCPConnection.h or TNCPConnection.cpp), but I couldn’t find a solution. Adding
template class CPConnectionBase<TNCPConnection>;
to the file TNCPConnection.cpp does not solve my linker problems, and adding
template<> class CPConnectionBase<TNCPConnection>;
to the file TNCPConnection.cpp gives me a compile time error:
error C2908: explicit specialization; ‘CPConnectionBase’ has already been instantiated
How can I get rid of the linker errors without making the implementation of the base class dependent of the header files of the derived classes?
Here is the skeleton of my code:
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)
{
...
}
The definition of
CPConnectionBase::start()must be available at the place where you explicitly instantiate the class – otherwise the function will not be instantiated, and this non-instantiation happens silently (with linker errors following).The standard solution is a header
CPConnectionBase.hppthat defines the template functions declared inCPConnectionBase.h. IncludeCPConnectionBase.hppinTNCPConnection.cppand explicitly instantiate there.