0

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.

Gaston
  • 115
  • 1
  • 7
  • Do you have a minimal reproducible example? One that can be used to generate this linker error with the methods? – unddoch Jun 09 '21 at 18:32
  • Is the error you're getting "Undefined reference to vtable for ..."? Or are some of the templated methods defined in a source (.cpp) file rather than in a header file? – 1201ProgramAlarm Jun 09 '21 at 21:40
  • @unddoch unfortunately I have no such code. I will see if I can find the time trying to generate a sample code – Gaston Jun 10 '21 at 18:08
  • No, the error is not about the vtable itself, but about each and every method entry in the vtable. In case of a vtable reference error it would be unlikely to solve it via a forced instantiation. But you are right I forgot to mention in my post that there are no method templates in these classes, only the classes themselves are templated. @1201ProgramAlarm – Gaston Jun 10 '21 at 18:13
  • Here a sample error message: /usr/bin/ld: CMakeFiles/google_tests_run.dir/argparser_test.cpp.o:(.data.rel.ro._ZTVN5gglib9ArgParser7details9_tArgTypeINS0_17TIntegerValueListEiEE[_ZTVN5gglib9ArgParser7details9_tArgTypeINS0_17TIntegerValueListEiEE]+0x40): undefined reference to `gglib::ArgParser::details::_tArgType::getValueList()' – Gaston Jun 10 '21 at 18:15
  • On the surface, sounds like an instance of [Why can templates only be implemented in the header file?](https://stackoverflow.com/q/495021/1670129) – Igor Tandetnik Jun 12 '21 at 13:45

0 Answers0