Beyond the Basics
Templates
Write code once for any type: function templates, class templates, multiple type parameters, non-type parameters and specialisation — the foundation of the STL.
Suppose you need maximum for int, double and string. Overloading means three copies of identical code. A template lets you write the code once with a placeholder type; the compiler generates each version you use. This is generic programming.
Function templates
#include <iostream>
#include <string>
using namespace std;
template <typename T>
T maximum(T a, T b) {
return (a > b) ? a : b;
}
template <typename T>
void swapAny(T &a, T &b) { T t = a; a = b; b = t; }
int main() {
cout << maximum(3, 9) << endl; // T = int
cout << maximum(2.5, 1.75) << endl; // T = double
cout << maximum(string("apple"), string("mango")) << endl;
cout << maximum<double>(4, 7.5) << endl; // T given explicitly
string a = "left", b = "right";
swapAny(a, b);
cout << a << " " << b << endl;
return 0;
}9 2.5 mango 7.5 right left
typename and class mean the same thing in a template parameter list: template <class T> is equally valid.
Templates with arrays
#include <iostream>
using namespace std;
template <typename T>
T sum(const T arr[], int n) {
T total = T(); // zero for numbers
for (int i = 0; i < n; i++) total += arr[i];
return total;
}
template <typename T>
int linearSearch(const T arr[], int n, const T &key) {
for (int i = 0; i < n; i++) if (arr[i] == key) return i;
return -1;
}
int main() {
int marks[] = {78, 85, 92};
double prices[] = {9.99, 24.5, 3.25};
char grades[] = {'A', 'B', 'O', 'C'};
cout << sum(marks, 3) << " " << sum(prices, 3) << endl;
cout << "'O' at index " << linearSearch(grades, 4, 'O') << endl;
return 0;
}255 37.74 'O' at index 2
Class templates
A class template describes a family of classes. The STL's vector<int> and stack<string> are class templates.
#include <iostream>
#include <string>
#include <stdexcept>
using namespace std;
template <typename T, int CAPACITY = 100> // a type parameter and a non-type parameter
class Stack {
T items[CAPACITY];
int top = -1;
public:
void push(const T &x) {
if (top == CAPACITY - 1) throw overflow_error("stack full");
items[++top] = x;
}
T pop() {
if (top == -1) throw underflow_error("stack empty");
return items[top--];
}
bool empty() const { return top == -1; }
int size() const { return top + 1; }
};
int main() {
Stack<int> numbers;
for (int i = 1; i <= 4; i++) numbers.push(i * i);
cout << "popping ints:";
while (!numbers.empty()) cout << " " << numbers.pop();
cout << endl;
Stack<string, 3> words; // capacity 3
words.push("templates"); words.push("are"); words.push("neat");
try { words.push("overflow!"); }
catch (const overflow_error &e) { cout << "error: " << e.what() << endl; }
cout << "words on stack: " << words.size() << endl;
return 0;
}popping ints: 16 9 4 1 error: stack full words on stack: 3
Two type parameters
#include <iostream>
#include <string>
using namespace std;
template <typename K, typename V>
class Pair {
public:
K key;
V value;
Pair(K k, V v) : key(k), value(v) {}
void show() const { cout << key << " -> " << value << endl; }
};
int main() {
Pair<string, int> p1("Asha", 92);
Pair<int, double> p2(7, 8.75);
p1.show();
p2.show();
return 0;
}Asha -> 92 7 -> 8.75
Template specialisation
Give a type its own special version when the generic code does not fit:
#include <iostream>
#include <cstring>
using namespace std;
template <typename T>
bool isEqual(T a, T b) { return a == b; }
template <> // full specialisation for C strings
bool isEqual<const char *>(const char *a, const char *b) { return strcmp(a, b) == 0; }
int main() {
char x[] = "hello", y[] = "hello";
cout << boolalpha << isEqual(4, 4) << " " << isEqual<const char *>(x, y) << endl;
return 0;
}true true
Without the specialisation, comparing two const char * would compare addresses, not text.
| Templates | Overloading | Macros |
|---|---|---|
| one definition, many types | one definition per type | text substitution |
| type-checked | type-checked | no type checking |
| code generated per type used | written by hand | expanded inline |
Test yourself
4 questions · pick an answer to check it instantly
- 1
What does
template <typename T>do?The compiler substitutes the real type forTwhen the template is used. - 2
For
template <typename T> T big(T a, T b), what doesbig(3, 4.5)do?Writebig<double>(3, 4.5)to choose the type explicitly. - 3
In
template <typename T, int N> class Buffer, what isN?Non-type parameters let you pass constant values such as array sizes. - 4
Which STL component is a class template?
vector<int>,vector<string>and so on are generated from one class template.