Imagine writing the exact same function twice, once for int and once for double, purely because C++ makes you declare types upfront. Templates exist specifically so you don't have to do that.

The problem, without templates

int maxInt(int a, int b) {
    return (a > b) ? a : b;
}

double maxDouble(double a, double b) {
    return (a > b) ? a : b;
}

These two functions are identical except for one word. Multiply this by every type you might ever want to compare, and you end up copying the same logic over and over, which is exactly the kind of repetition that should set off alarm bells.

The same thing, with a template

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

std::cout << findMax(3, 7);        // 7
std::cout << findMax(3.5, 2.1);    // 3.5

T here isn't a real type — it's a placeholder, filled in automatically by the compiler based on whatever you actually pass in. Call findMax with two ints, and the compiler generates an int version behind the scenes. Call it with two doubles, and it generates a double version instead, all from this one piece of code you wrote once.

Templates on classes, too

template <typename T>
class Box {
public:
    T value;
    Box(T v) { value = v; }
};

Box<int> intBox(5);
Box<std::string> stringBox("hello");

This might already look familiar — std::vector<int> and std::vector<std::string>, which you've already seen in the vectors tutorial, are themselves built using exactly this template mechanism. vector isn't magic; it's a template class from the standard library, the same idea shown here, just written by people who thought about it very carefully.

A word of honesty

Templates can get genuinely complicated fast once you start combining several of them together, and template error messages have a well-earned reputation for being some of the least friendly in all of programming — a single mistake can produce a wall of text that seems to haven'thing to do with the actual problem. None of that should stop you from using basic templates like the ones shown here; it's just worth knowing that the deep end exists, so you aren't caught off guard later.

Why bother learning this at all

Templates are exactly how C++'s standard library manages to give you containers like vector, and algorithms like sort, that work with practically any type you throw at them. Understanding roughly how templates work demystifies a lot of what is actually happening every time you use std::vector or std::sort, rather than treating them as unexplainable built-in magic.