Concepts / Understanding Template Compilation

Understanding Template Compilation

To use a template, its full definition, not merely its declaration, must be in scope.

  • Programming

Using a Container Whose Code You Cannot See

Suppose your program needs a container that holds a list of numbers. In C++ the standard library offers vector, which is a template: a single description that the compiler can turn into a concrete container for whatever element type you request. A vector of integers and a vector of strings both come from the same template. Using a template is not as simple as calling a function whose signature you already know. The compiler has to be able to see the full template in order to produce the specialized code you need. This article is about that requirement, often called the scope requirement for templates, and about the trouble it can cause when something goes wrong.

What do you think happens?

To write vector<int> in your program, is it enough for the compiler to know that a template named vector exists, or must it see the full template definition?

  • A declaration that vector exists is enough

  • The compiler must be able to see the full template definition

Reveal answer
Answer:

The compiler must be able to see the full template definition.

To use a template, its full definition, not merely its declaration, must be in scope. The compiler needs the body of the template to generate the specialized code for the element type you request.

Declarations Versus Definitions

Definition

A declaration tells the compiler that something exists and describes its shape. A definition supplies the complete body that goes with that shape.

For ordinary functions and classes you may often see a declaration in one place and a definition in another, and a program can still make progress using the declaration alone in many situations. For templates, the distinction carries real weight. A declaration by itself is not enough to use the template, because the compiler needs the complete body to produce the specialized code for each element type you request.

Template nametells the compiler itexistsComplete bodythe full template textShapedescribes its formSpecialized codecan be generated forvector<int>togetherenables
What does a template declaration tell the compiler, and how does that differ from what the full definition provides?

Tracing a vector<int> Use Through the Compiler

Follow one use from start to finish. When your source code contains a use such as vector<int>, the compiler knows that it needs a container specialized for int. To produce that specialized code, it must be able to see the template definition. If the full definition is in scope at that point, the compiler can proceed. If only a declaration is visible, the template cannot be used as written.

Use of vector<int>Template name foundFull definition inscope?Generate specializedcodefor int elementsTemplate cannot beusedonly a declaration isvisiblelook upcheck bodyyesno
When the compiler sees a use like vector<int>, what must it be able to see, and at which step does it need the template body rather than just its declaration?
Worked example

Deciding Whether vector<int> Can Be Used

A source file contains a use of vector<int>. Only a declaration of the vector template is visible at that point. Can the compiler produce the specialized container?

  1. 1
    Identify the requirement

    To use a template, its full definition must be in scope. A declaration alone does not satisfy this.

  2. 2
    Check what is visible

    The compiler sees only the declaration, which says the template exists and describes its shape.

  3. 3
    Apply the rule

    Without the complete body, the compiler cannot generate the specialized code for int elements.

  4. 4
    Fix the scope

    Making the full definition available, through a standard header such as vector, lets the same use succeed.

Result

The use cannot compile with only a declaration in scope. Once the full definition is in scope, the compiler can produce the specialized container for int.

The Role of the vector Header

The standard header vector holds the definition of the vector template. When your program includes that header, the full definition of the template becomes available to the compiler, and you can use vector with your own element types. The header is therefore not just a name tag. It carries the complete template that the compiler needs.

Source file#include <vector>vector headervector definitionthe complete templatevector<int> usecontainspulls inholdsmakes possible
How does a line like #include <vector> connect your source file to the template definition that the compiler needs?
cpp
Notes on the code
  • The include line brings the full vector template definition into the file.
  • vector<int> asks the compiler to produce a container specialized for int.
  • Because the definition is in scope, the use of vector<int> can be compiled.

If the include line were removed, the same use would rely on a template definition that is no longer in scope. This is the practical meaning of the scope requirement: the header is the link between your code and the body the compiler must read.

Why Template Errors Surface Late

A type error involving a template can be detected uncomfortably late in the compilation process. The compiler discovers the problem only after it combines information from several places: the template definition, the place where it is used, and the types supplied at that use. The mistake depends on how these pieces fit together, so the compiler cannot always report it at the moment a programmer might first expect.

Source fileCompilervector template bodyError report1. uses vector of a given type2. combines template body with use3. mismatch found inside body4. reports error in library text
Where in the compilation sequence does a type mismatch inside a template body get detected, and why does the error point into library code rather than the line that caused it?

Mistakes Beginners Make With Template Scope

  • Common mistake

    Assuming a declaration alone is enough to use a template

    Why it fails

    The compiler must see the full template definition to generate the specialized code for the element type requested.

    Do this instead

    Make sure the header that provides the definition, such as vector, is included before the use.

  • Common mistake

    Treating the standard header as just a name tag

    Why it fails

    A header such as vector carries the complete template the compiler needs, not only the name.

    Do this instead

    Think of an include line as bringing the template body into scope for the compiler.

  • Common mistake

    Reading only the first line of a long template error

    Why it fails

    The error can point into library code while the root cause is the use in your own file.

    Do this instead

    Trace back from the reported location to the line where you supplied the element type.

Tracing Scope in a Small Program

EASY

A program uses std::vector<double> in a function, but the file does not include the vector header anywhere above that use. Trace what the compiler can see at the point of use. Does it have the full template definition in scope? What change would make the use valid?

Hints
  • Ask which step in the flowchart needs the template body rather than only its declaration.
  • The standard header vector is where the definition of the vector template is provided.
  • Adding the include line before the use puts the full definition in scope.

Key Takeaways

  • To use a template, its full definition, not merely its declaration, must be in scope.
  • A declaration says a template exists and describes its shape, while a definition supplies the complete body the compiler needs to generate specialized code.
  • The standard header vector holds the definition of the vector template, so including it makes the template usable with your own element types.
  • Because the compiler combines information from the template definition, the use, and the supplied types, template type errors can be detected late and produce hard-to-read messages, so trace them back to the use that caused them.

Related concepts

More concepts starting with U