Variadic templates — parameter packs, fold expressions
1. Parameter packs — WHAT they are
Three places the ... appears (HOW to read it):
| Position | Meaning |
|---|---|
typename... Ts |
declare a type pack |
Ts... args |
declare a value pack |
args... (after) |
expand the pack |
2. Recursive expansion — the pre-C++17 way (DERIVE it)
Before fold expressions, you processed a pack by peeling off the head, recursing on the tail:
// Base case: no arguments left
void print() { }
// Recursive case: peel 'first', recurse on the 'rest' pack
template<typename T, typename... Rest>
void print(T first, Rest... rest) {
std::cout << first << ' ';
print(rest...); // expand: call print on the remaining pack
}WHY a base case is needed: recursion shrinks the pack by one each call. Without the no-arg
overload, the final print() call wouldn't compile — there'd be nothing to stop the recursion.
3. Fold expressions — the C++17 way (the 80/20 win)
Recursion is verbose (two functions for one idea). Fold expressions collapse a pack with a binary operator in one line.
template<typename... Ts>
auto sum(Ts... xs) {
return (xs + ...); // unary right fold: x1 + (x2 + (x3 + ...))
}DERIVE the expansion of sum(1,2,3):
Why? Unary right fold nests from the right. + is associative so the value is 6 either way.

4. Worked examples
5. Common mistakes
Flashcards
What does typename... Ts declare?
Ts.How do you get the number of elements in a pack Ts?
sizeof...(Ts) (a constexpr size_t).Where does ... mean "declare a pack" vs "expand a pack"?
Expand (xs + ...) for xs = 1,2,3.
1 + (2 + 3) = 6 (unary right fold, nests from right).Expand (... - xs) for xs = 1,2,3.
(1 - 2) - 3 = -4 (unary left fold, nests from left).Which 3 operators allow a unary fold over an empty pack, and their identities?
&&→true, ||→false, ,→void().Why does recursive pack processing need a base-case overload?
How do you safely sum a pack that might be empty?
(0 + ... + xs).What's the syntax to call f on every element of pack args?
(f(args), ...); or f(args)... inside a call.Why are parentheses mandatory in a fold expression?
... uses; it's a syntax rule.Recall Feynman: explain to a 12-year-old
Imagine a magic gift-wrapping machine. You don't know if you'll hand it 1 toy or 10 toys, but it
wraps all of them no matter how many. A parameter pack is the "pile of toys", and ... is
you saying "do this for every toy in the pile". A fold is like stacking the toys: (x + ...)
means "add them all into one box", starting from the right and squishing them together until just
one box (the answer) is left. The computer builds the exact wrapping steps before the program even
runs — so it's both flexible AND safe.
Connections
- Templates and Generics — variadic templates are the general case of Function Templates.
- std::tuple — built on parameter packs;
std::make_tupleis variadic. - Perfect Forwarding —
template<typename... Ts> f(Ts&&... a){ g(std::forward<Ts>(a)...); }. - Recursion — pre-C++17 pack processing is structural recursion on the type list.
- constexpr and Compile-time Computation —
sizeof...and folds are evaluated at compile time. - Operator Overloading — folds work with any binary operator, including overloaded ones.
Concept Map
Hinglish (regional understanding)
Intuition Hinglish mein samjho
Dekho, kabhi-kabhi humein aisa function chahiye jo kitne bhi arguments le sake — jaise
printf. Lekin printf type-safe nahi hai. Variadic templates is problem ko solve karte hain:
template<typename... Ts> likho aur ab Ts ek parameter pack ban gaya — yaani "ek dher of
types". Ts... args matlab values ka dher. Jab tum ... ko naam ke aage lagaate ho to pack
declare hota hai, aur peeche lagaate ho (jaise args...) to pack expand hota hai. Count
chahiye? sizeof...(Ts) use karo — ye sizeof se alag hai, ye batata hai kitne elements hain.
Purane C++ me pack ko process karne ke liye recursion karni padti thi: ek argument peel karo
(first), baaki ko rest... me daalo, aur dobara call karo — saath me ek empty base-case function
zaroori hota tha warna recursion kabhi rukti nahi. C++17 me aaye fold expressions jo same kaam
ek line me kar dete hain: (xs + ...) saare elements ko + se jod deta hai. Parentheses lagana
mandatory hai, warna compile error.
Sabse important point: left fold vs right fold. (... op xs) left fold hai (left se nest hota
hai), (xs op ...) right fold hai (right se). + ke liye fark nahi padta, par -, / ya string
banane me direction se result badal jaata hai — diagram me dekho 1-2-3 ka answer 2 ya -4 ho sakta
hai! Aur ek trap: agar pack khaali ho sakta hai, to unary fold (jaise (xs + ...)) compile
error dega — tab binary fold init ke saath use karo: (0 + ... + xs). Sirf &&, ||, aur ,
operators empty pack ke saath chalte hain (true, false, void).