I have am developping a shared library (Linux & Windows, where current testing runs on Linux using gcc). One part of this library is a quite complex command line parser using class templates and normal classes.
The inheritance path is like this (I omit namespaces here):
// normal class for polymorphism
class _tArgTypeBaseClass;
// class template (CRTP idea) for implementing common code
template<class C,typename T> class _tArg : public _tArgTypeBaseClass;
// example class (multiple types have been implemented
class TIntegerValueList : public _tArg<TIntegerValueList, int32_t>
// template class to implement non list specialization
template<class PARENT, typename T> class _tArgNoList : public PARENT
// typedef (currently typedef, I know I could be using "using")
typedef _tArgNoList<TIntegerValueList, uint32_t> TIntegerValue;
In this class tree simple template methods are implemented in the header file but more complex methods are in the cpp unit file.
Currently, I am testing the library with google test, and all used to work fine, i.e. the cpp methods were all available for the google test program to run its tests. These test are all currently only using TIntegerValueList (no other type yet and no T...Value specialization.
I also have to note that all _tArg template methods used to be virtual methods declared pure virtual in the base class _tArgTypeBaseClass.
Now I did a few changes in the class tree and ended up with the test program not linking anymore with linker reporting unknown references to all vtable methods in _tArg<TIntegerValueList, int> (aka int32_t)
The change that introduced the problem is probably that now I changed one method to being non-virtual because it became type-dependent. Note that this is a method of TIntegerValueList (not the template _tArg). So I commented out the pure virtual method declaration and removed the override keyword from the actual methods in the TxxxValueList classes.
Does somebody have an explanation why this happens?
P.S.: I know that I can force instantiation via template class _tArg<TIntgereValueList, int32_t>; best using the extern template in the header file, which I currently do as a workaround. But I prefer to avoid this, if possible, as it is error-prone when adding new value types.