C & C++ DISCUSSION

Why do I get undefined reference errors when a C++ template is defined in a .cpp file?

Started by aqibsaeed C++ templatesundefined referenceexplicit instantiationheader fileslinker errors
4 replies 248 views 5 participants
Latest activity · 30 Sep 2026

Why do I get undefined reference errors when a C++ template is defined in a .cpp file?

aqibsaeed C & C++ Forum
#1

I split a ring buffer class into RingBuffer.h, with the declaration template <typename T, size_t N> class RingBuffer, and RingBuffer.cpp with the member function definitions, the way I do for ordinary classes. Every file compiles, but linking fails with an undefined reference to RingBuffer<unsigned char, 64>::push(unsigned char).

Moving the definitions into the header makes the error go away. Why does a template behave differently from a normal class, and is putting everything in the header the only option?

Community replies 4

Re: Why do I get undefined reference errors when a C++ template is defined in a .cpp file?

#2

A template is not code; it is a recipe from which the compiler generates code once it sees a concrete set of arguments. Each .cpp file is compiled on its own. When main.cpp uses RingBuffer<uint8_t, 64> it sees only the declaration from the header, so it emits a call to push and leaves the symbol for the linker.

When RingBuffer.cpp is compiled the definitions are present, but nothing in that file uses RingBuffer<uint8_t, 64>, so no instantiation is generated there either. Neither object file contains the function, and the linker reports it missing.

Re: Why do I get undefined reference errors when a C++ template is defined in a .cpp file?

#3

Putting the definitions in the header is the usual answer, and it does not produce duplicate symbol errors. Implicit template instantiations, like inline functions, may be emitted in several object files, and the linker keeps a single copy.

If you want the header to stay readable, move the definitions to a separate file such as RingBuffer.tpp and #include it at the bottom of the header, inside the include guard. Do not add that file to the build as a translation unit of its own; it is only ever compiled as part of the header.

Re: Why do I get undefined reference errors when a C++ template is defined in a .cpp file?

#4

The other option is explicit instantiation. If the argument combinations are known in advance, keep the definitions in RingBuffer.cpp and add one line per combination at the end of that file: template class RingBuffer<uint8_t, 64>;. This forces the compiler to generate every member for that type in that object file, and the linker finds them.

The drawback is that using RingBuffer<uint16_t, 32> somewhere else brings the link error back until another line is added. It suits libraries with a small fixed set of types, and it shortens build times because the bodies are compiled once. A matching extern template class RingBuffer<uint8_t, 64>; in the header tells other files not to instantiate it themselves.

Re: Why do I get undefined reference errors when a C++ template is defined in a .cpp file?

#5

On a microcontroller, watch the code size. Every distinct argument set is a separate copy of each member function that is used: RingBuffer<uint8_t, 64> and RingBuffer<uint8_t, 128> share no code although only the size differs. If that matters, put the size-independent logic in a non-template base class that works on a pointer and a length, and let the template be a thin wrapper that supplies the storage.

To see what you are paying, run nm --size-sort -C on the ELF file or read the map file; there is one symbol per instantiated member, with its size. Implicit instantiation only generates the members that are actually called, whereas explicit instantiation generates all of them.

TEP COMMUNITY