Concepts / Templates and Type Deduction

Templates and Type Deduction

Metaprogramming is the use of C++ features for compile-time computation, and template metaprogramming is the form that involves templates.

  • Programming

A Question the Compiler Must Answer

Imagine you are writing a function that only makes sense for whole numbers. You want the program to refuse to compile if someone passes it a type such as double, instead of failing in some confusing way later. The difficulty is that ordinary C++ code runs only after the program has already been built. Ordinary code therefore cannot answer the question 'is this a whole-number type?' on your behalf. What you need is a way to ask questions about types while the compiler is still working.

What do you think happens?

A function is written to accept only whole-number types. A caller passes it a double. When should the rejection happen?

  • When the program is running, after a confusing failure

  • While the compiler is working, before the program exists

Reveal answer
Answer:

While the compiler is working, before the program exists.

The source frames the goal as refusing to compile bad code. A question the compiler can answer during translation can reject the code early, before any program runs.

Compile Time Versus Run Time

C++ includes mechanisms for compile-time computation. These are features that let part of the work of a program happen when the compiler translates the source code, not when the resulting program runs. The benefit described for these mechanisms is tighter type checking and better performance than would otherwise have been possible.

It helps to read the process as a sequence of stages. The compiler reads the code, evaluates the compile-time questions the code asks, and only then produces a program. By the time the program starts running, the answers to those questions are already fixed. The running program simply uses them.

Read source codecompiler reads the codeEvaluate compile-timequestionstype functions answerProduce programanswers already fixedProgram runsuses the fixed answersthenthenthen
Which steps happen during compilation, and what is already fixed when the program executes?

The stages above are the core of the idea. Everything left of the program-running step happens while the compiler works. Everything at and after that step is ordinary execution, and it can only rely on what was decided earlier.

Why It Is Called Metaprogramming

Definition

Metaprogramming is the use of C++ features for compile-time computation. Template metaprogramming is the form of metaprogramming that involves templates.

The word meta points at the idea that the program is computing about other code, specifically about types, instead of only computing ordinary values. Ordinary programming manipulates data the program will use later. Metaprogramming manipulates information about types while the compiler works, so the eventual program is shaped by those answers.

Type Functions as Questions About Types

The source introduces type functions as one of the mechanisms behind compile-time computation. Think of a type function as a question. It takes a type as input, checks something about that type, and gives back an answer. The answer is determined while the compiler runs, so the rest of the code can treat it as a fixed fact.

The questions can be simple, such as whether a type is an integer type. They can also be about related types, such as what kind of element a container's iterator refers to. Because the compiler can answer these questions before the program exists, a bad choice of type can be rejected early. This is the source of the tighter type checking the source describes.

Type inputfor example doubleType functionasks a question about thetypeAnswera type or a valueRest of the codeuses the fixed answerpassed incomputed at compile timeavailable as fact
How does a type function take a type, run a check, and produce an answer before the program runs?

Tracing a Type Question in Code

The following illustrative example applies the whole-number scenario from the opening. It uses the standard library predicate std::is_integral, which asks whether a type is an integer type and exposes the answer through its value member. The static_assert line asks that question at compile time and stops compilation if the answer is false.

Code walkthrough
#include <type_traits>

template <typename T>
void only_whole_numbers(T value) {
    static_assert(std::is_integral<T>::value, "T must be an integer type");
    // body that uses value goes here
}

int main() {
    only_whole_numbers(42);   // T is int: the question answers true, so this compiles
    only_whole_numbers(2.5);  // T is double: the question answers false, so compilation stops
}
  1. 1
    The template parameter T stands for whatever type the caller passes in.
  2. 2
    When the compiler sees only_whole_numbers(42), T becomes int, and std::is_integral<int>::value is true, so static_assert passes.
  3. 3
    When the compiler sees only_whole_numbers(2.5), T becomes double, and std::is_integral<double>::value is false, so static_assert reports the message and the program is not built.
  4. 4
    No part of this check waits for the program to run. The answer is already known when the compiler finishes.
  • std::is_integral<T> is a type predicate: a type-level question with a true or false answer
  • static_assert evaluates the answer while the compiler runs
  • The call with 2.5 fails to compile rather than failing later at run time
Worked example

Reading the Answer to a Type Question

Given a type question that asks whether a type is an integer type, what does the compiler conclude for int and for double?

  1. 1
    Identify the input

    The type passed to the question is the input. For the first case it is int, and for the second it is double.

  2. 2
    Run the check

    The predicate asks whether the input is an integer type. int is an integer type, and double is not.

  3. 3
    Read the produced answer

    For int the answer is true. For double the answer is false.

  4. 4
    Act on the fixed fact

    A false answer can be used to reject the code during compilation, before the program is ever run.

Result

The question yields true for int and false for double, and that answer is fixed before the program runs.

Standard Library Tools for Reading Types

The source presents two facilities that the standard library provides as concrete examples of compile-time questions. They are worth keeping separate in your mind. One reports facts about a type, and the other tests a yes or no question about it.

Choosing Between a Predicate and iterator_traits

ToolQuestion it asksForm of the answer
std::is_integral<T>Is T an integer type?true or false
std::is_same<T,U>Are T and U the same type?true or false
std::iterator_traits<Iter>What facts does this iterator type report?member typedefs such as value_type and iterator_category

Type predicates test a property, while iterator_traits reports properties

When you need a decision, such as whether to allow a type, reach for a predicate. When you need to know a detail about an iterator, such as its element type, reach for iterator_traits. Both are compile-time questions, so both are answered before the program runs.

Mistakes Beginners Make With Compile-Time Questions

  • Common mistake

    Expecting a type predicate to be checked while the program runs

    What it looks like

    Writing a normal if statement on std::is_integral<T>::value and assuming it protects the program at run time.

    Why it fails

    The predicate's answer is produced while the compiler works. Ordinary code runs after the program is built, so it cannot be the place where the type question is first answered.

    Do this instead

    Use the answer as a compile-time guard, such as a static_assert, when the goal is to reject bad types before the program exists.

  • Common mistake

    Treating iterator_traits as a yes or no test

    What it looks like

    Expecting iterator_traits<Iter> to return true or false for an iterator.

    Why it fails

    iterator_traits reports information about an iterator type, through member typedefs such as value_type. It does not test a property with a boolean answer.

    Do this instead

    Read the member typedef you need, such as value_type, and use a predicate only when you need a true or false decision.

  • Common mistake

    Assuming the compiler asks these questions at run time, which hides the reason the technique exists

  • Common mistake

    Confusing a type with a value that the program computes

    Why it fails

    Metaprogramming manipulates information about types during compilation. Its answers are fixed before execution starts, so they are not values the program computes later.

    Do this instead

    Ask whether the question is about a type while the compiler works. If it is, its answer belongs to compile time.

Practice: Classify Each Question

EASY

For each question below, decide whether the right tool is a type predicate or iterator_traits, and whether the answer is true or false or a set of member typedefs. Questions: (1) Should the compiler reject a type that is not an integer type? (2) What element type does an iterator refer to? (3) Are two given types exactly the same type?

Hints
  • A question that needs a yes or no answer points toward a type predicate.
  • A question that asks what an iterator refers to or what kind of iterator it is points toward iterator_traits.
  • std::is_same<T,U> is the predicate that compares two types.

Key Takeaways

  • Metaprogramming is the use of C++ features for compile-time computation, and template metaprogramming is the form that involves templates.
  • Compile-time computation lets part of a program's work happen while the compiler translates the source, which supports tighter type checking and better performance.
  • A type function takes a type, asks a question about it, and produces an answer that is fixed before the program runs.
  • Type predicates such as std::is_integral<T> and std::is_same<T,U> give true or false answers, while iterator_traits reports information about an iterator type.

Related concepts

More concepts starting with T