Bytebook Compiler

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.

4 min read5 runnable examples4-question quiz

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

C++
#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;
}
Output
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

C++
#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;
}
Output
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.

C++
#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;
}
Output
popping ints: 16 9 4 1
error: stack full
words on stack: 3

Two type parameters

C++
#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;
}
Output
Asha -> 92
7 -> 8.75

Template specialisation

Give a type its own special version when the generic code does not fit:

C++
#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;
}
Output
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. 1

    What does template <typename T> do?

  2. 2

    For template <typename T> T big(T a, T b), what does big(3, 4.5) do?

  3. 3

    In template <typename T, int N> class Buffer, what is N?

  4. 4

    Which STL component is a class template?