1

I've been having some issues lately with my custom written general purpose vector code, which relies on templates for functionality. I am reluctant to include the implementation in the header file (as is common with templates), as this would add significantly to the compilation time. So I have instead manually instantiated the desired class in the .cpp file. However, this still results in an undefined reference error. I have reduced the code to the following snippet, which still generates an error:

matrixd.cpp

#include "matrixd.h"

namespace math
{
    template class _vec2<float>;
    template<class T> _vec2<T>::_vec2() {}
}

matrixd.h

#pragma once
namespace math
{ 
    template <class T>
    class _vec2
    {
    public:
        T x, y;
        _vec2<T>();
        void reset();
    };

    typedef _vec2<float> vec2;
}

test.cpp

#include "matrixd.h"

int main()
{
    math::_vec2<float> v;
}

Error message:

In function main': source.cpp:(.text+0x10): undefined reference to math::_vec2::_vec2()' collect2: error: ld returned 1 exit status

Any help would be appreciated! :)

Cameron Tacklind
  • 5,764
  • 1
  • 36
  • 45
  • Hello! If this is a duplicate, would you kindly direct me to the appropriate solution? I saw similar questions, but the issue that the posters were having was that they were unaware of manual template instantiation. –  May 31 '15 at 22:03
  • To declare a constructor you only need to write `_vec2()` not `_vec2()` – Jonathan Wakely May 31 '15 at 22:06
  • You could put the definitions in the header file and add an _explicit instantiation declaration_ to the header (i.e. an "extern template" declaration) which tells the compiler it doesn't need to instantiate the members because you will provide an explicit instantiation definition in some translation unit (in this case in matrixd.cpp) – Jonathan Wakely May 31 '15 at 22:09
  • @JonathanWakely I believe both are legal, though `_vec2()` is definitely cleaner. – T.C. May 31 '15 at 22:11
  • 1
    My generic advice with regard to templates: If possible, don't use source files to define your template functions. Instead make your templates a header-only implementation. It makes life much easier. With regard to the leading underscore on `_vec2`: Don't do that, either. Just because the standard library uses leading underscores doesn't mean you should. In fact, it means you shouldn't. The standard library uses leading underscores to avoid conflicts with user code. While legal in this instance, user code with leading underscores is not a good practice. – David Hammen May 31 '15 at 22:17
  • I for one think there is a lot of value in *not* putting definitions in header files. It's often easier if you do in the short term, but there are issues that can crop up later. And it can enable much faster compile times. – Cameron Tacklind Apr 22 '21 at 00:24

1 Answers1

5

A explicit instantiation definition (template class _vec2<float>; in your code) instantiates only the member functions that have been defined at the point of explicit instantiation. _vec2<T>::_vec2() was defined after the explicit instantiation definition, and so is not explicitly instantiated.

The fix is to swap the two lines:

namespace math
{
    template<class T> _vec2<T>::_vec2() {}
    template class _vec2<float>;
}
T.C.
  • 133,968
  • 17
  • 288
  • 421