Foundations — Concepts (C++20) — constraining templates
This page assumes nothing. Every symbol, keyword and squiggle used on the parent page is unpacked here, in an order where each item leans only on the ones before it. If a line on the parent page confused you, find that symbol below.
0. The picture we keep coming back to
Think of a template as a cookie-cutter, and a type (a label like "whole number" or "text" — defined properly in Section 1) as a slab of dough. The cutter stamps out a real function or class once you hand it a specific dough. A concept is a sign taped to the cutter: "only chocolate or sugar dough — no rock." The sign is checked at the door, not after the cookie is baked and broken.
Figure s01 (below): the teal cookie-cutter carries a dashed blank slot labelled T; the orange sign taped on top reads "numeric dough only"; on the right, an int plug fits (green true) while a string block is turned away (orange false). This is the mental image for every section that follows.

1. type — what a value is
Picture: a type is the shape of a socket. A round plug (int) fits a round socket; it will not go into a square one (a decimal where a whole number is expected). Operations like + are the "prongs" — a socket either has them or it doesn't.
Why the topic needs it: concepts are questions about types. Before you can ask "does this type support +?" you must accept that a type is a thing carrying a fixed set of allowed operations. See Templates — function & class templates for where types get plugged in.
2. template<typename T> — the cookie-cutter and its blank
template<typename T> // "T is a type-shaped blank"
T add(T a, T b) { return a + b; } // body uses that blankPicture: the cutter shape from figure s01, with T written on the empty slot. Later you fill that slot with a real type (int, double, ...) — same cutter, different cookies. The exact notation for filling the slot is <...>, unpacked in Section 5.
Why the topic needs it: a concept is attached to that blank to restrict what may fill it. No blank, nothing to constrain. This is the single prerequisite the whole parent note stands on.
3. constexpr and "compile time" — when the check happens
Picture: two clocks. Clock A ticks while the chef (compiler) reads the recipe. Clock B ticks while the diner (running program) eats. A constexpr value — and every concept check — happens entirely on clock A — by the time clock B starts, every constraint has already passed.

Why the topic needs it: the parent note says a concept is "a constexpr bool template ... never runs at runtime." That sentence is meaningless until you see these two clocks. See constexpr — compile-time evaluation.
4. bool, predicate, and true/false
Picture: a light switch — up (true) or down (false). A concept is a switch whose position depends on which type you feed it: fed a whole-number type it lights up, fed text it stays down.
Why the topic needs it: a concept is a predicate. Numeric<T> (where <...> is Section 5) reads as "is T numeric?" and lights up true or false. Everything else in the parent note is machinery for computing that one light switch.
5. <...> — the angle brackets (giving a template its type)
Picture: the blank slot on the cutter (figure s01) being physically filled. <int> drops int into the slot.
Why the topic needs it: every concept use in the parent — Numeric<T>, std::integral<T>, std::same_as<T> — is angle-bracket substitution. Recognising <...> as "fill the blank" is essential. Now that both the blank (Section 2) and the filling notation are defined, add<int> and Numeric<int> are fully earned.
6. std:: — the standard library's name tag
Picture: a labelled drawer. Everything in the std drawer is standard-issue and already tested. std::integral, std::floating_point, std::same_as, std::convertible_to, std::begin, std::cout, std::string, std::vector all live there.
Why the topic needs it: concepts like Numeric are built out of ready-made std:: concepts. Now that std:: and <...> are both defined, the phrases "text" (std::string) and "list of ints" (std::vector<int>) used loosely earlier are fully spelled out. See type_traits — std::integral, std::floating_point.
7. ||, && — combining true/false answers
Picture: two switches wired together. For ||, either switch alone lights the bulb. For &&, you need both switches up.
template<typename T>
concept Numeric = std::integral<T> || std::floating_point<T>;
// true if T is a whole number OR T is a decimal numberWhy the topic needs it: the parent's very first concept, Numeric, is an or of two simpler predicates. A requires-expression's list of requirements is implicitly an and — every line must compile.
8. concept Name = ...; — naming a predicate
Picture: writing the words on the sign taped to the cutter (figure s01). Before, the rule lived nowhere; now it has a reusable label.
Why the topic needs it: naming turns a scary boolean formula into one readable word you can reuse and put in error messages ("std::string did not satisfy Numeric").
9. requires (two of them) — the confusing twin keywords
The parent note stresses there are two different requires. Here is the picture that separates them.

10. -> in a requirement, plus *, std::begin, decltype
Before we can read the parent's decltype(*std::begin(r)), four small symbols need names.
Picture: the arrow -> is a customs checkpoint after the expression compiles: the result must show the right "type passport." The * is a finger following the cursor from std::begin down to the actual element it points at. See auto and decltype.
Why the topic needs it: the compound requirement ({e} -> C) is one of the four requirement kinds, and the parent's Printable concept uses decltype(*std::begin(r)) to name "the element type" so it can test whether elements are streamable.
11. Overloading & subsumption — why more rules win
Picture: two doormen. Door A: "wholes only." Door B: "positive wholes only." A +5 satisfies both, but B is stricter, so the crowd is funnelled through B. An unsatisfied door isn't an error — that guest simply can't use that door.
Why the topic needs it: this is the parent's "killer feature." See Overload Resolution & Subsumption. Note the old, clumsy way of doing this — SFINAE and std::enable_if — which concepts replace.
Prerequisite map
Related tooling this feeds into: Ranges library (C++20) (whose Printable-style range concepts appear in the parent's worked example) and the full parent note Hinglish version.
Equipment checklist
A type is best described as
template<typename T> in one phrase
T, filled in later.typename vs class inside template<...>
Compile time vs run time
What the constexpr keyword guarantees
A bool is
true or false.A predicate is
Numeric<int> means
Numeric predicate with the blank T set to int, giving true or false.The std:: prefix means
std::vector<int> reads as
int (bracket = fill the element blank).A || B is true when
A, B is true.A concept definition does what
requires-clause vs requires-expression
Do the braces { a + b } compute a+b?
a + b would compile, not its value.A simple requirement vs a compound one
; with no arrow, asks only "does it compile?"; compound = { e } -> C, also pins down the result type.A type requirement looks like
typename T::value_type; — asserts that a nested type exists.A nested requirement looks like
requires Numeric<T>; — bolts another whole constraint inside the factory.The dereference * in *std::begin(r) gives
r.std::begin(r) returns
r.{ expr } -> C checks
expr compiles AND the type of its result satisfies concept C.decltype(e) means
e would have.