Templates
By the end of this lesson you'll be able to write one piece of code that works with any type — function templates, class templates, multiple type parameters, defaults, and a first taste of specialization — the exact technique the entire C++ Standard Library is built on.
Part of the free C++ course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
What You'll Learn
💡 Real-World Analogy
A template is a cookie cutter . The cutter defines the shape ; the dough is the type . Press it into sugar dough and you get a sugar cookie; press it into gingerbread and you get a gingerbread cookie — same shape, different material. You write the shape once ( template < typename T > ) and the compiler stamps out a concrete version for every type you actually use. You don't get an int version until you press the cutter into an int .
1. Function Templates & Type Deduction
Without templates you'd copy maxOf once per type: one for int , one for double , one for string . A function template replaces all of them with a single recipe. You write template < typename T > above the function, then use T wherever a type would go. T is a placeholder : the compiler stamps out a real version the moment you call it. And thanks to type deduction , you usually don't even name the type — the compiler reads your arguments and works T out for itself.
Your turn. The program below is almost complete — write the template < typename T > line and the comparison so minOf returns the smaller value. Fill in the two blanks marked ___ using the hints, then run it.
2. Class Templates, Multiple Params & Defaults
Templates aren't just for functions — a class template makes a whole class generic. Box < T > can hold an int , a string , or anything else. You can declare multiple type parameters too: Pair < K, V > has two independent placeholders. And a default template argument ( typename V = int ) lets callers leave a parameter off and get a sensible default — just like a default function argument. One gotcha: class templates need the type written in < ... > when you create an object; deduction only happens automatically for function templates.
Now you try. Creating an object from a class template means putting the type inside the angle brackets. Fill in the two blanks so price is a Box of double and name is a Box of string :
3. Specialization & Where Errors Appear
Sometimes the general template is wrong for one specific type. Template specialization lets you hand-write a dedicated version for exactly that type, using template < > . The classic case is comparing C-strings: the general > compares pointer addresses , not the text, so you specialize to compare the real characters. This section also shows the single most confusing thing about templates: errors appear at instantiation , not at definition. A template you never call is never type-checked — the compiler only complains when you actually use it with a type that doesn't fit.
🔎 Deep Dive: typename vs class
You'll see both template < typename T > and template < class T > in real code. For declaring a type parameter they mean exactly the same thing . Modern code prefers typename because the placeholder doesn't have to be a class — it can be int , double , a pointer, anything.
Pro Tips
- 💡 Keep template code in headers: the compiler needs the full body to generate each type's version, so definitions live in .h / .hpp , not .cpp .
- 💡 Let deduction work: write maxOf(5, 3) , not maxOf < int > (5, 3) — only add explicit < ... > when the compiler can't deduce or you want a specific type.
- 💡 The STL is templates: vector < T > , map < K,V > , and sort() are all templates — everything you learn here you'll reuse constantly.
- 💡 Read template errors top-down: find the first error and the call site that triggered it; the rest is usually noise.
Common Errors (and the fix)
- "undefined reference" linker error: you split a template into a .cpp file. Template definitions must be visible where they're used — put the whole template in the header.
- Long, cryptic instantiation errors: templates are only checked when used, so the error explodes deep inside generated code. Read from the top, fix the first error, and look at the call that instantiated it.
- "no matching function" on missing typename : when a dependent name is a type you must say so, e.g. typename vector < T > ::iterator it; — forgetting typename there is a classic compile error.
- "could not deduce template argument 'T'": you called maxOf(5, 3.14) — one int , one double , so T can't be both. Make the types match or force it: maxOf < double > (5, 3.14) .
- "no operator > for type X": you used a template with a type that doesn't support the operation inside it (comparing incompatible T s). Use a type that defines the operator, or specialize the template for that type.
📋 Quick Reference
Task
Code
Function template
template < typename T > T id(T x);
Call (deduced)
maxOf(3, 7)
Call (explicit type)
maxOf < double > (3, 7)
Class template
template < typename T > class Box { ... } ;
Instantiate class
Box < int > b(42);
Multiple params
template < typename K, typename V >
Default arg
template < typename V = int >
Specialization
template < > T maxOf < T > (...) { ... }
Frequently Asked Questions
Mini-Challenge: a generic clamp()
No blanks this time — just a brief and an outline. Write a function template clamp that pins a value between a low and high bound, then prove it's generic by calling it with both int s and double s. Check your output against the example in the comments.
🎉 Lesson Complete
- ✅ template < typename T > makes a function generic; T is a type placeholder
- ✅ Type deduction lets the compiler pick T from your arguments
- ✅ Class templates ( Box < T > ) make whole classes generic
- ✅ Use multiple params ( Pair < K, V > ) and default args ( V = int )
- ✅ Specialize with template < > when one type needs different behaviour
- ✅ Template errors appear at instantiation — read them top-down
- ✅ Next lesson: the Standard Template Library — containers and algorithms built entirely on templates
Practice quiz
Which line correctly declares a function template with one type parameter T?
- template typename T
- template <typename T>
- typename <template T>
- template T<typename>
Answer: template <typename T>. template <typename T> introduces T, a placeholder for any type, before the function or class.
In the call maxOf(10, 20) with template <typename T> T maxOf(T, T), what type is T deduced as?
- double
- int
- long
- It must be stated explicitly
Answer: int. Both arguments are int literals, so template type deduction makes T = int. No explicit <int> is needed.
What does template <typename V = int> add to a class template?
- A default template argument for V
- A forced specialization
- A runtime default value
- A second base class
Answer: A default template argument for V. = int is a default template argument: if the caller omits V, it becomes int, just like a default function argument.
Is there any difference between template <typename T> and template <class T> for declaring a type parameter?
- typename allows non-class types only
- class allows non-class types only
- No difference at all
- class is faster to compile
Answer: No difference at all. For declaring a type parameter they are identical. typename is preferred because the placeholder need not be a class.
When is a function template actually type-checked for a given type?
- At its definition
- When it is instantiated (used) with that type
- Only at link time
- Never
Answer: When it is instantiated (used) with that type. A template is only checked when instantiated, which is why errors appear at the call site, not the definition.
Creating an object from a class template Box<T> requires what?
- Nothing — the type is always deduced
- The type written in angle brackets, e.g. Box<int>
- A specialization first
- A virtual destructor
Answer: The type written in angle brackets, e.g. Box<int>. Before C++17 CTAD, class templates need the type spelled out, e.g. Box<int> b(42). Function templates deduce; classes (here) do not.
Why specialize maxOf for const char* (C-strings)?
- To make it run faster
- Because the general > compares pointer addresses, not the text
- Because const char* has no operator>
- To avoid a linker error
Answer: Because the general > compares pointer addresses, not the text. For const char*, the general > compares pointer addresses. The specialization compares the actual characters instead.
What syntax begins a full template specialization?
- template <T>
- specialize <T>
- template <>
- template default <>
Answer: template <>. template <> introduces a full specialization — a hand-written version for one specific type.
Why must template definitions usually live in header files?
- Headers compile faster
- The compiler needs the full body visible where the template is used
- Templates cannot appear in .cpp files at all
- To avoid name mangling
Answer: The compiler needs the full body visible where the template is used. Each concrete version is generated at the point of use, so the full definition must be visible there — hiding it in a .cpp causes undefined-reference linker errors.
What does maxOf(5, 3.14) cause, given template <typename T> T maxOf(T a, T b)?
- T = double automatically
- T = int automatically
- A deduction failure — T can't be both int and double
- A runtime exception
Answer: A deduction failure — T can't be both int and double. One argument is int, the other double, so T cannot be deduced to a single type. Make the types match or force maxOf<double>(5, 3.14).
Continue this course
- Previous: Inheritance & Polymorphism
- Next: Standard Template Library