I’m trying to create a C++ class, with a templated superclass. The idea being, I can easily create lots of similar subclasses from a number of superclasses which have similar characteristics.
I have distilled the problematic code as follows:
template_test.h:
template<class BaseClass> class Templated : public BaseClass { public: Templated(int a); virtual int Foo(); }; class Base { protected: Base(int a); public: virtual int Foo() = 0; protected: int b; };
template_test.cpp:
#include 'template_test.h' Base::Base(int a) : b(a+1) { } template<class BaseClass> Templated<BaseClass>::Templated(int a) : BaseClass(a) { } template<class BaseClass> int Templated<BaseClass>::Foo() { return this->b; }
main.cpp:
#include 'template_test.h' int main() { Templated<Base> test(1); return test.Foo(); }
When I build the code, I get linker errors, saying that the symbols Templated<Base>::Templated(int) and Templated<Base>::Foo() cannot be found.
A quick Google suggests that adding the following to main.cpp will solve the problem:
template<> Templated<Base>::Templated(int a); template<> int Templated<Base>::Foo();
But this does not solve the problem. Adding the lines to main.cpp does not work either. (Though, interestingly, adding them to both gives ‘multiply defined symbol’ errors from the linker, so they must be doing something…)
However, putting all the code in one source file does solve the problem. While this would be ok for the noddy example above, the real application I’m looking at would become unmanageable very fast if I was forced to put the whole lot in one cpp file.
Does anyone know if what I’m doing is even possible? (How) can I solve my linker errors?
I would assume that I could make all the methods in class Templated inline and this would work, but this doesn’t seem ideal either.
With templated classes, the definitions must be available for each translation unit that uses it. The definitions can go in a separate file, usually with
.inlor.tccextension; the header file#includes that file at the bottom. Thus, even though it’s in a separate file, it’s still#included for each translation unit; it cannot be standalone.So, for your example, rename
template_test.cpptotemplate_test.inl(ortemplate_test.tcc, or whatever), then have#include 'template_test.inl'(or whatever) at the bottom oftemplate_test.h, just before the#endifof the include guard.Hope this helps!