Templates in C++: Reusable Parameterized Code with Worked Examples

Learn how one C++ template produces type-specific functions and classes. Follow exact calls, calculations, deduction failures, and practical corrections.

KnowledgeGate Team

Exam prep & CS education

Updated 13 Nov 20266 min read
Templates in C++: Reusable Parameterized Code with Worked Examples

Writing larger(int, int) and larger(double, double) repeats one comparison under two type names. A function template replaces the duplicates with one parameterised definition, but the compiler still has to select one T, validate operator>, and form a concrete specialisation. Non-type parameters and a broader runnable survey belong in Templates in C++: Function and Class Templates with Runnable Examples. Deduction, explicit arguments, body requirements and definition visibility are four separate failure points in this smaller trace.

C++ template parameters remove duplicated type-specific bodies

Without a template, the two functions may begin like this:

cpp
int larger(int a, int b) { return (a > b) ? a : b; }
double larger(double a, double b) { return (a > b) ? a : b; }

Only the type changes. The comparison and selection algorithm stay the same. Copying it again for long creates another body to maintain and another place where an inconsistent edit can appear.

A template is a pattern parameterised by a type or value. In the example below, T is the template parameter, while int is one possible template argument. Instantiation forms a usable specialisation for an argument. Specialisation can mean that resulting type-specific form or an explicitly customised case. Templates operate at compile time. They are not runtime dynamic dispatch.

Review functions, references and class basics first in the C++ Tutorial: The Complete Learning Path from First Program to STL. Those foundations make it easier to read T as a compile-time type parameter rather than a runtime variable.

C++ function templates: read the type contract token by token

cpp
template <typename T>
T larger(T a, T b) {
    return (a > b) ? a : b;
}

template <...> introduces the template-parameter list. typename T declares T as a type parameter. The return type is T, and both function parameters are also T, so one chosen type must satisfy all three positions. In this body, values of that type must support operator> because the conditional expression compares a and b.

The equivalent spelling template <class T> declares the same kind of type parameter. typename is used here because it states the role of T directly.

The declaration does not promise that every imaginable type will work. It does not erase types at runtime, and it does not automatically make unrelated argument types compatible. For a chosen T, the comparison must be a valid expression, and the return statement must produce a value compatible with T. The compiler checks those requirements when the corresponding specialisation is needed.

C++ template deduction: trace successful and conflicting calls

Flowchart traces C++ template deduction for four successful calls and one conflicting mixed-type call.

Trace each call from its arguments to the selected T, then evaluate the comparison:

cpp
int first = larger(14, 9);
double second = larger(3.25, 7.50);
int third = larger<int>(6, 11);
double fourth = larger<double>(4, 6.5);

Call

How T is chosen

Comparison

Result

larger(14, 9)

Deduced as int

14 > 9 is true

14

larger(3.25, 7.50)

Deduced as double

3.25 > 7.50 is false

7.50

larger<int>(6, 11)

Explicitly int

6 > 11 is false

11

larger<double>(4, 6.5)

Explicitly double; 4 converts to 4.0

4.0 > 6.5 is false

6.5

Now consider larger(4, 6.5). The first argument suggests T = int, while the second suggests T = double. Deduction cannot select one T, so the call fails at compile time. The compiler does not silently choose the wider type during template argument deduction.

Make the argument types agree with larger(4.0, 6.5), which deduces double, or state the argument explicitly with larger<double>(4, 6.5). In the second repair, normal conversion changes 4 to 4.0 after T is fixed as double.

Flowchart tracing larger(T a, T b): T = int for 14 and 9, T = double for 3.25 and 7.50, and a failed deduction for 4 and 6.5.

C++ class templates: one parameter creates distinct object types

A class template makes T part of each object's type. For C++20 constraints, bound invariants and clamp behaviour, use the C++ Function and Class Templates: Build One Type-Safe Range Pattern. Measurement<T> instead exposes unconstrained class instantiation and member-expression validity with the smallest useful state.

cpp
template <typename T>
class Measurement {
    T value;
public:
    explicit Measurement(T initial) : value(initial) {}
    T shifted(T delta) const { return value + delta; }
};

Measurement<int> count(18);
Measurement<double> reading(21.25);

count is a Measurement<int>. Its call count.shifted(4) calculates 18 + 4 = 22. reading is a Measurement<double>, and reading.shifted(0.75) calculates 21.25 + 0.75 = 22.0.

Measurement<int> and Measurement<double> are distinct instantiated types even though one source template defines both. The constructor and shifted() parameter use the same chosen T for each object.

The member body adds a requirement that deduction alone cannot prove: T + T must be valid, and its result must convert back to T. A type can therefore be deduced successfully and still fail when the compiler instantiates shifted().

C++ template instantiation and specialisation solve different jobs

Calling larger(14, 9) requires the compiler to form the int version. Calling larger(3.25, 7.50) similarly requires the double version. This is implicit instantiation. It does not follow that every use must enlarge the final binary, since compiler and linker optimisation may merge or remove code.

Mechanism

Purpose

Primary template

Supplies the general parameterised pattern

Normal overload

Supplies another signature or behaviour and participates in overload resolution

Explicit specialisation

Customises the template for one exact argument set and starts with template <>

An explicit function-template specialisation declaration starts with template <>:

cpp
template <> const char* larger<const char*>(const char* a, const char* b);

Raw C strings need a content-aware comparison policy. Applying ordinary > to pointers would compare addresses, not the character sequences they represent.

C++ template errors: identify the phase before changing code

Use each error to identify the missing rule:

  • larger(4, 6.5) -> conflicting deductions -> make both arguments the same type or specify double.

  • Assuming any type works -> invalid > or + expression -> check every operation used in the template body for the proposed type.

  • Definition kept only in a separately compiled .cpp file -> another translation unit cannot instantiate it -> normally keep the full template definition in a header, unless the program follows a deliberate explicit-instantiation design.

  • Treating Measurement<int> and Measurement<double> as the same type -> conversion errors -> remember that they are distinct types, and provide code that permits any required conversion.

  • Calling templates runtime polymorphism -> wrong execution model -> separate compile-time instantiation from virtual dispatch at runtime.

One more code-reading check helps. larger('b', 'a') deduces T = char. Both operands have the same type, the built-in comparison is valid, and 'b' > 'a' is true, so the function returns 'b'. This result concerns individual character values. It does not establish content-comparison behaviour for strings or raw C-string pointers.

C++ template questions: predict types before outputs

Exam-style and interview-style questions ask you to identify parameters and arguments, determine a deduced type, predict output, detect deduction conflicts, distinguish function and class templates, choose general or specialised behaviour, and test whether body operations are valid.

These checkpoints test type deduction, output prediction, and deduction conflicts:

  1. larger(8, 12) deduces T = int; 8 > 12 is false, so the result is 12.

  2. larger(2.5, 1.25) deduces T = double; 2.5 > 1.25 is true, so the result is 2.5.

  3. larger(8, 12.0) fails deduction because the arguments suggest int and double. Make them agree or provide an explicit template argument.

Answer the three checkpoints before compiling. For exercises across more languages and placement-coding topics, continue with Coding & Skill Development Courses.

C++ templates: the short version

Find duplicated logic where only a type varies, replace that type with T, and confirm that every expression in the body works for the chosen T. Trace type deduction before tracing output. In particular, larger(4, 6.5) is a deduction problem, not a numeric-comparison problem.

Retype larger, predict all four successful results without compiling, then add the invalid mixed-type call and repair it both ways. For a structured sequence of concepts, MCQs and coding practice, continue with the C++ Programming Course.