In C++, templates allow a programmer to create generic functions or classes. Templates are blueprints that can work with many data types, saving the programmer from the hassle of writing the same code logic multiple times for different data types. However, templates can only be implemented entirely in the header files because of how C++ code is compiled. C++ code is preprocessed, compiled, assembled, and finally linked before it can be executed. During the linking phase, any function calls and variables defined within the source file and elsewhere are resolved by linking them to their actual addresses, i.e., their complete definitions in their respective header files. Therefore, all implementations, even for templates, must be included in header files.
In the following code example, a simple template class is declared in the template.h
header file. However, its complete definition is given in the template.cpp
file. The template object is created in the main.cpp
file for the integer data type. Finally, the getter and setter functions—which are implemented in the template.cpp
file—are called.
The following code will give a linker error, as shown in figure 1 below.
Run the code below to analyze the error.
#include "template.h"using namespace std;int main(){mytemplate<int> object;object.set_value(10);cout<<object.get_value()<<endl;}
To understand the error above, we’ll need to grasp how compilation works in C++. It starts from the main
function in the main.cpp
file. The preprocessor generates a temporary file. The preprocessor generates this file by expanding all directives and macros in the source code. The directives can be user-defined header files or predefined libraries. The temporary file is fed to the compiler. An assembler file containing machine code is outputted. The assembler file becomes the input to the assembler, which generates an object file. The object file is finally converted to an executable by the linker once all symbols are resolved. Symbol resolution is the process in which the linker associates any function calls and variables—not given in main.cpp
—with its actual memory address or definition. These are usually present in other header files converted to object files.
Specifically for the code above, the linker would have generated the following code only if the code definition for these functions was present in the header file. Since the implementations are present in the template.cpp
file, which is not directly accessible to the linker, these function definitions aren’t generated, resulting in the linker error shown in figure 1.
void mytemplate::set_value(int value){my_value = value;}int mytemplate::get_value(){return my_value;}
The code below shows the correct implementation of a template. The definitions of the template functions are given in their respective header file. Run the code below to see the correct output.
#ifndef mytemplate_h#define mytemplate_h#include <iostream>template<typename T>class mytemplate{private:T my_value;public:void set_value(T value);T get_value();};template<typename T>void mytemplate<T>::set_value(T value){my_value = value;}template<typename T>T mytemplate<T>::get_value(){return my_value;}#endif
In conclusion, for linkers to find the complete template definition in the linking phase, templates must be defined inside header files.
Free Resources