Introduction
If you wrote larger for int, then again for double and again for string, you would have three copies of the same idea to maintain. A template lets you write it once and leave the type to be filled in.
How it works
template <typename T> introduces a placeholder for a type. The compiler looks at each use, works out T, and generates a real function for that type. This happens at compile time, so there is no cost when the program runs.
template <typename T>
T larger(T a, T b) {
return a > b ? a : b;
}
Giving the type yourself. Usually the compiler can work it out. larger<string>("apple", "pear") states it, because quoted text would otherwise be treated as a character pointer.
Requirements. The template only works for types that support what it does. larger needs >, so using it with a type that has no > is a compile error, often with a long message. Read the first line of that message, because it names the problem.
Class templates are written the same way. Every use of the class states the type:
#include <iostream>
#include <string>
using namespace std;
template <typename T>
class Box {
T value;
public:
Box(T v) : value(v) {}
T get() const {
return value;
}
};
int main() {
Box<int> a(5);
Box<string> b("hello");
cout << a.get() << " " << b.get() << endl;
return 0;
}The standard containers are class templates, which is why you write vector<int>.
Syntax
template <typename T>
void show(const T& value) {
cout << value << endl;
}
template <typename K, typename V>
class Entry { ... };
Example
#include <iostream>
#include <string>
using namespace std;
template <typename T>
T larger(T a, T b) {
return a > b ? a : b;
}
int main() {
cout << larger(3, 9) << endl;
cout << larger(2.5, 1.5) << endl;
cout << larger<string>("apple", "pear") << endl;
return 0;
}Line by line
template <typename T>says thatTis a type to be decided later.larger(3, 9)makes the compiler create a version forint.larger(2.5, 1.5)creates a version fordouble.larger<string>states the type, so the quoted text becomes strings."pear"is larger than"apple", because strings compare in alphabetical order.
Expected result
9
2.5
pear
In the real world
The whole standard library is built on templates, which is why one sort works on almost any kind of data. They give the speed of hand-written code with the convenience of generic code.
Common mistakes
- Mixing types, as in
larger(1, 2.5), becauseTcannot be two things. - Putting a template's body in a
.cppfile apart from its uses. Templates usually live in headers. - Being scared by long error messages. Start at the first line.
- Using a template when a simple function would do.
Best practices
- Use a template only when you truly need several types.
- Take large values by
const T&. - Give each type parameter a short, clear name.
Summary
Templates are patterns for functions and classes. The compiler makes real code for each type used, with no cost at run time. A type must support what the template asks of it.
Quick check
Key takeaways
- A template avoids repeating the same code for each type.
- The type must support the operations the template uses.
- vector and map are themselves templates.
Practice problems for this lesson
My notes
Write down what you want to remember from this lesson. Notes are saved on this device as you type, and appear on your dashboard.