Translation Units and Include Files
Each translation unit that uses a template must receive the definition through an include. A definition that exists only in a different file does not make the template usable in the file that calls it.
Why Having a Template Is Not Enough
A template is a way of writing code once and letting the compiler produce concrete versions of it for the types you actually use. That flexibility comes with a rule that surprises many programmers: having a template somewhere in your program is not enough for the compiler to use it. The compiler needs to see the template's definition at the point where you use it. A declaration that merely announces that a template exists does not give the compiler the body it needs to build a version of that template.
Keep this question in mind as you read: if one file declares a template and another file tries to call it, what has to be visible to that second file for the call to work? The answer depends on the difference between a declaration and a definition, and on the way compilation handles templates. Once you see that difference, a whole category of confusing compiler errors becomes predictable.
Declarations Versus Definitions in Scope
Scope is the reason definitions and declarations behave differently here. Both can be visible at the same time, yet the template still cannot be used unless the definition is among the things the compiler can see at the place of use. A declaration tells the compiler the template's name and its shape, but it does not carry the body. A definition carries the body, and that body is what the compiler needs in order to produce a concrete version for a particular type.
Why Templates Have No Separate Compilation
Ordinary C++ code is often split across several source files, and each source file is compiled on its own. You can compile one .cpp file into an object file, compile another .cpp file separately, and then link the results together. Templates do not follow this pattern. There is no separate compilation of templates, so a template cannot be compiled once in its own file and then linked in later for every caller.
Because of this, the template definition must be included in every translation unit that uses it. A translation unit that calls the template needs to have the definition itself, delivered through an include. The definition is not handed over as a finished, precompiled piece of code that other files can pick up at link time. Each file that uses the template has to receive the definition and work with it directly.
Each translation unit that uses a template must receive the definition through an include. A definition that exists only in a different file does not make the template usable in the file that calls it.
The Translation Unit as the Unit of Work
A translation unit is one source file together with everything it includes. This is the unit the compiler works on. When you compile a .cpp file, the compiler does not see just that file; it sees the file with all of its included headers pulled in as part of its text. That combined whole is the translation unit, and it is what decides what names and definitions are available at each point in the code.
Because a template's definition is not compiled in isolation, each translation unit that needs the template must receive the definition itself. The include directive is the mechanism that does this. When a header is included, its contents become part of the file the compiler is reading, and any template defined there is visible to every line of code that follows the include.
The diagram shows the practical consequence. The definition lives in one header, but it reaches every translation unit that uses it through an include. If a translation unit does not include the definition, that unit cannot use the template, even if the rest of the program has it. The header is therefore the single place where the definition is written, and the include is the path by which it arrives everywhere it is needed.
Tracing a Template Through Two Source Files
The following example is an original illustration, not taken from the source. It places a template definition in a header and uses it from two separate source files. Read it as a trace: follow what each file can see when the compiler reaches a call to the template.
Tracing the calls in each translation unit
a.cpp calls largest(3, 7) and b.cpp calls largest(10, 4). Both include largest.h. What does each translation unit see when the compiler reaches its call?
- 1Start with a.cpp
The preprocessor replaces the include line with the contents of
largest.h, so the template definition becomes part ofa.cpp's text before the call on the main line. - 2Check the call in a.cpp
When the compiler reaches
largest(3, 7), the definition is already in scope. It can build the version that works with int values. - 3Start with b.cpp
b.cppincludes the same header, so it receives its own copy of the definition text as part of its own translation unit. - 4Check the call in b.cpp
When the compiler reaches
largest(10, 4), the definition is in scope in this unit too. The unit does not depend ona.cppfor the template body.
Each translation unit receives the definition through its own include and builds what it needs. Neither file relies on the other for the template body, which is exactly what the absence of separate compilation for templates requires.
What Goes Wrong When the Definition Is Missing
Now suppose the header keeps only the declaration, and the definition is left out. The file below is an original illustration of that mistake, built on the same two source files as before.
With this header, b.cpp still includes largest.h and still calls largest(10, 4). The declaration makes the name known, but the compiler has no body to turn into a version for int. The source states that a header containing only a template declaration cannot support template calls in files that include it. The error that results depends on the toolchain: it may be reported while compiling the calling file, or it may appear as an undefined reference when the program is linked.
Common Mistakes With Template Headers
Common mistake Putting only the template declaration in the header
What it looks likelargest.h contains template <typename T> T largest(T a, T b); and nothing else.
Why it failsA declaration announces the template but does not provide the body the compiler needs to build a version for a type.
Do this insteadPlace the full definition in the header, so every file that includes it can see the body at the point of use.
Common mistake Assuming one file's definition is enough for another file
What it looks likea.cpp includes largest.h with the full definition, and b.cpp calls largest without including anything that defines it.
Why it failsTemplates have no separate compilation, so the definition must be included into every translation unit that uses it.
Do this insteadInclude the header that holds the definition in each source file that calls the template.
Common mistake Believing that a declaration in a header makes the template usable everywhere
Why it failsBoth declaration and definition can be visible at once, yet the template still cannot be used unless the definition is in scope at the place of use.
Do this insteadCheck what is visible at the call site, not just whether the name is declared somewhere in the program.
Common mistake Compiling the template in its own .cpp file and expecting it to be linked later
Why it failsA template cannot be compiled once in its own file and linked in later for other callers.
Checking Your Understanding
A header named tools.h contains only the declaration template <typename T> T clamp(T v, T lo, T hi); and no body. The file main.cpp includes tools.h and calls clamp(5, 0, 3). A second file, util.cpp, includes tools.h and contains no call to clamp. Which translation unit cannot use the template, and what change would make main.cpp able to use it?
Hints
- Ask what the compiler must see at the place where clamp is called, not whether the name is declared.
- A template body must be available in each translation unit that uses it, and it cannot be compiled once and linked in later.
- Consider what would have to go into
tools.hformain.cppto get the body through its include.
Key Takeaways
- A template is usable only when its definition, not just its declaration, is in scope at the place where it is used.
- Templates have no separate compilation, so the definition must be included in every translation unit that uses the template.
- A translation unit is a source file together with everything it includes, and the include directive delivers the template definition to each unit that needs it.
- A header with only a template declaration cannot support calls to the template in files that include it, and the resulting error may appear at compile time or as an undefined reference at link time depending on the toolchain.