Foundations — Variadic templates — parameter packs, fold expressions
Before you can read any line of the parent note, you must own every symbol it throws at you. This page lists them in build-order: each new symbol only uses ones already defined above it. Nothing is assumed.
0. The very first picture: what "the pile" looks like
When you call an ordinary function you hand it a fixed number of values:
add(3, 4) // exactly two thingsA variadic function instead accepts a pile of values — 0, 1, 2, 5, a hundred — and we draw that pile as boxes sitting in a row.
Look at the figure. The blue boxes are the individual values you passed. The yellow bracket underneath, labelled args, is the name for the whole pile at once. That single yellow name is the thing the rest of this topic manipulates. Keep this picture in your head: one name, many boxes.
1. template — WHY it comes first
Before variadics, you need the idea of a template.
template<typename T> // T is the blank
T bigger(T a, T b) { return a > b ? a : b; }Why the topic needs it: a parameter pack is a template blank that holds many types instead of one. You cannot understand "pack" without first understanding "one blank". See Templates and Generics and Function Templates for the full story of the stamp.
Reading guide for the pieces:
template<...>— "here comes a recipe with blanks".typename T— "the blank is a type, and I'll call itT".T a, T b— ordinary parameters that happen to use the blank.
2. typename — WHAT the blank holds
Why we care: in template<typename... Ts> (the parent's very first formula) the word typename tells you the pile Ts is a pile of types, not a pile of values. Two different piles will appear (types and values) and this keyword marks the type one.
3. The ellipsis ... — the single most important symbol
Everything hard about this topic is one symbol used in two directions. We take it slowly with a figure.
Study the two halves of the figure.
Left half (declare): the dots are on the left of the name Ts. This is the machine's intake — it scoops many separate things into one pile named Ts. That is why the parent writes typename... Ts.
Right half (expand): the dots are on the right of a small pattern. Here the machine unpacks the pile, repeating the pattern once per box. So args... becomes a0, a1, a2, and the pattern f(args)... becomes f(a0), f(a1), f(a2) — the whole shape to the left of the dots is copied for each box.
Why the topic needs it: without ... you'd have to name each box (a0, a1, ...) by hand, but you don't know how many boxes exist. The ellipsis is the "for every box" instruction that makes an unknown-length pile writable in one line.
4. Two kinds of pack — types vs values
The parent uses two piles that look almost identical. Separate them now.
They come as a matched pair: each value in args has a type in Ts, box for box.
template<typename... Ts> // Ts = pile of TYPES
void f(Ts... args); // args = pile of VALUES (one per type)5. sizeof... — HOW MANY boxes (not how many bytes)
You'll meet the two words attached to sizeof...:
So sizeof...(Ts) is "a compile-time count, of type size_t". Nothing more mysterious than that.
6. Binary operators and association — the ground under folds
A fold expression (the parent's Section 3) collapses a pile using a binary operator. You must own two words first.
Now the subtle one — which pair goes first when you chain them.
The figure shows the same three numbers 1, 2, 3 folded two ways.
- Left fold (top, blue): squeeze the leftmost pair first →
(1-2)-3 = -4. - Right fold (bottom, yellow): squeeze the rightmost pair first →
1-(2-3) = 2.
Same numbers, same operator, different answer — because - cares about grouping. This is exactly why the parent has four folds (left/right × unary/binary): the direction the dots sit tells you which pairing happens first.
Bridge to the parent: in a fold, the ... sits on the side that "opens up deepest". Dots on the left → left-associative. Dots on the right → right-associative. That single rule decodes all four folds.
7. Recursion — the old engine before folds
The parent's Section 2 processes a pile without folds, using recursion.
This matters because it explains why fold expressions were invented: recursion needs two functions (the peeler and the empty-pile stopper) to express one idea, and folds do it in a single line.
8. Two more names you'll bump into
You don't need to master these to read the parent — just recognise the names.
The prerequisite map
Read it top to bottom: templates give you a blank, typename says the blank is a type, the ellipsis lets one blank hold many things, and the two branches (folds vs recursion) are the two ways to use the pile.
Equipment checklist
Cover the right side and answer aloud. If any stumps you, re-read its section above.
A template in one phrase
What typename reserves a spot for
The two jobs of ... and how to tell them apart
Difference between the pack Ts and the pack args
Ts is a pile of types; args is the matching pile of values.What sizeof...(Ts) returns
size_t, NOT a byte size.Why sizeof... ≠ sizeof
sizeof = bytes of one object; sizeof... = number of pack elements.What "left-associative" means for a - b - c
(a - b) - c.Why fold direction matters for - but not +
- gives different answers under different grouping; + is order-independent.