Visual walkthrough — Template specialization — full and partial
We build up one idea at a time. Nothing below assumes you memorised anything from the parent note — we re-earn every word.
Step 1 — A template is a stamp that makes many boxes
WHAT. Start with the most generic thing: a primary template.
template<class T>
struct Box { /* generic recipe */ };Read template<class T> out loud as: "for any type you hand me, called T, here is how to build a Box." The word struct just means "a little bundle of data and functions." T is a blank slot — a placeholder waiting for a real type like int or double.
WHY. The compiler cannot ship a box for every type in advance — there are infinitely many types. So instead it ships a stamp: a machine that, when you write Box<int>, presses out a fresh Box with the word int filling the T slot. This pressing is called instantiation.
PICTURE. The stamp on the left; three pressed boxes on the right, each with a different type poured into the slot.

Step 2 — Every type is a point; a template covers a REGION of types
WHAT. Imagine drawing all possible types as dots on a big sheet — int, double, int*, char*, pair<int,char>, and so on. Now draw a boundary around the set of types a given stamp is willing to serve. We call that boundary the stamp's match region.
WHY. The whole selection problem becomes visual once we think in regions. The primary template<class T> serves everything — its match region is the entire sheet. A specialization will draw a smaller region inside it. "Which recipe wins" turns into "which region is smallest around the point X."
PICTURE. The full sheet of type-dots. A dashed outer rectangle labelled "primary T — matches ALL types" wraps every dot.

Step 3 — Full specialization: a region containing exactly ONE point
WHAT. A full specialization pins all parameters to concrete types, so its region shrinks to a single dot.
template<> // no slots left — zero free parameters
struct Box<int> { // this exact type: int
/* custom recipe for int only */
};Term by term:
template<>— the angle brackets are empty because you filled in every slot; there is nothing left for the compiler to deduce.Box<int>— names the one instantiation you are replacing. This is the dot.
WHY. Sometimes the generic recipe is wrong, slow, or impossible for exactly one type (recall std::vector<bool> bit-packing from the parent). Full specialization lets you hijack that single point without renaming anything — callers still write Box<int>.
PICTURE. The sheet from Step 2, now with a tiny circle lassoing the single int dot, labelled "full spec Box<int> — 1 type". The double and int* dots stay outside, still served by the primary.

Step 4 — Partial specialization: a region shaped like a FAMILY
WHAT. A partial specialization pins only the shape of the type, leaving some slots free.
template<class T> // T is still a free slot
struct Box<T*> { // but the type must look like "pointer to something"
/* custom recipe for any pointer */
};Term by term:
template<class T>— one slot remains free; that is what makes it partial rather than full.Box<T*>— the pattern. The*means "matches any type of the form pointer-to-T."int*matches withT = int;char*matches withT = char;intdoes not match (no*).
WHY. Often you want one custom recipe for a whole family — "all pointers," "all pair<A,B> — not a single type and not everything. Since function overload resolution already handles function families, C++ only allows partial specialization on class templates (the parent's mistake-callout: functions get overloads instead).
PICTURE. The sheet again, now with a medium oval enclosing every *-dot (int*, char*, double*), labelled "partial spec T* — the pointer family". It sits inside the primary rectangle but is bigger than any single point.

Step 5 — The selection rule, as a walk from outside in
WHAT. Put a query type X as a star on the sheet. The compiler collects every stamp whose region contains the star, then keeps the smallest such region.
WHY. "Smallest region containing the star" is precisely the plain-English rule "most specialized match wins." A full spec (single point) beats a partial (family), which beats the primary (everything) — but only among those that actually contain the star.
PICTURE. For X = int*: the star lands inside the primary rectangle and inside the T* oval, but outside the Box<int> point-circle. Two nested regions contain it; the inner T* oval wins. Arrows show the compiler "shrinking inward" until no smaller region contains the star.

Step 6 — Comparing two regions: partial ordering
WHAT. When you have several partials, "smaller region" needs a precise test, called partial ordering. Spec A is more specialized than B if every type matching A also matches B, but not the reverse.
WHY. "Smaller" was intuitive on the sheet; the compiler needs a mechanical version. Partial ordering is exactly "A's region B's region and they are not equal" — set containment, but computed by a matching game rather than by drawing.
PICTURE. Two ovals. pair<int,B> (fix the first slot to int, second free) sits inside pair<A,B> (both free). Every pair<int, something> is also a pair<A,B>, but not every pair<A,B> has int first — so the inner one is more specialized.

Step 7 — The degenerate case: two regions that CROSS (ambiguity)
WHAT. What if two partials overlap but neither sits fully inside the other? Then for a type in the overlap, there is no smallest region — and the compiler refuses to guess.
template<class A, class B> struct M {};
template<class A> struct M<A, int> {}; // region: "second slot is int"
template<class B> struct M<int, B> {}; // region: "first slot is int"
M<int, int> m; // ERROR: ambiguousTerm by term:
M<A,int>covers everything whose second parameter isint.M<int,B>covers everything whose first parameter isint.M<int,int>lives in both regions at once — the crossing zone.
WHY. Neither region is a subset of the other (each contains points the other misses: M<char,int> is only in the first; M<int,char> only in the second). So partial ordering gives no winner. Rather than pick arbitrarily, the compiler emits an ambiguity error — a feature, protecting you from silent wrong choices.
PICTURE. Two overlapping ovals forming a Venn diagram. The lens-shaped overlap holds the single dot M<int,int>, flagged in amber with "AMBIGUOUS — no smallest region."

The one-picture summary
Everything above is one idea: nest the regions, drop the star, keep the innermost region that still contains it. Full spec = a point, partial spec = a shaped family, primary = the whole sheet. Overlapping-but-not-nested regions with the star in the overlap = ambiguity.

Recall Feynman: retell the whole walkthrough in plain words
Picture a giant sheet of paper with a dot for every type in existence. The generic template is a lazy fence drawn around all the dots — it'll serve anyone. A full specialization is a tiny lasso around exactly one dot: "for int, use my recipe." A partial specialization is a medium loop around a family of dots that share a shape — "all pointers," "all pairs." Now someone asks for a type: drop a star on that type's dot. The compiler looks at every fence, loop, and lasso that surrounds the star and keeps the tightest one — because the tightest region means "you clearly meant this special case." A one-dot lasso beats a family loop beats the everything-fence. The only way it breaks is if two loops cross and the star sits in the crossing region: now there's no single tightest loop, so the compiler throws up its hands and says "ambiguous" rather than guess. Fix it by drawing an even tinier lasso — a full spec — right on the disputed dot.
Recall
Which region-shape is a full specialization? ::: A single point — all parameters pinned. Which region-shape is a partial specialization? ::: A shaped family — some parameters free, the type's structure constrained. Winner among matching regions? ::: The smallest region still containing the query type. Two partials overlap but neither is inside the other, and X is in the overlap — result? ::: Ambiguity error; no most-specialized choice exists. Formal test for "A more specialized than B"? ::: match(A) ⊆ match(B) and match(A) ≠ match(B).
Related vault topics: Templates — function and class basics · Type Traits and std::is_pointer · SFINAE and enable_if · Overload Resolution vs Specialization · std::vector<bool> special case · Tag Dispatch and Policy-based Design · constexpr if (C++17) — alternative to specialization