C++ Fold Expressions | "Parameter Pack Folding" Guide
이 글의 핵심
C++17 fold expressions: unary/binary folds over parameter packs (+, &&, comma)—less boilerplate than recursive templates.
What are Fold Expressions?
C++17 fold expressions are a syntax for “folding” a parameter pack in variadic templates using an operator. Without requiring recursive templates, you can apply operators like +, &&, <<, etc., to the entire pack at once. This can make your code more concise, especially after mastering template basics.
// Before C++17: Recursion
template<typename T>
T sum(T value) {
return value;
}
template<typename T, typename... Args>
T sum(T first, Args... args) {
return first + sum(args...);
}
// C++17: Fold Expression
template<typename... Args>
auto sum(Args... args) {
return (... + args); // Unary left fold
}
cout << sum(1, 2, 3, 4, 5) << endl; // 15
4 Types of Folding
// 1. Unary right fold: (args op ...)
template<typename... Args>
auto sum1(Args... args) {
return (args + ...); // ((1 + 2) + 3) + 4
}
// 2. Unary left fold: (... op args)
template<typename... Args>
auto sum2(Args... args) {
return (... + args); // 1 + (2 + (3 + 4))
}
// 3. Binary right fold: (args op ... op init)
template<typename... Args>
auto sum3(Args... args) {
return (args + ... + 0); // ((1 + 2) + 3) + 0
}
// 4. Binary left fold: (init op ... op args)
template<typename... Args>
auto sum4(Args... args) {
return (0 + ... + args); // 0 + (1 + (2 + 3))
}
Supported Operators
// Arithmetic operators
(... + args) // Addition
(... - args) // Subtraction
(... * args) // Multiplication
(... / args) // Division
// Logical operators
(... && args) // AND
(... || args) // OR
// Bitwise operators
(... & args) // AND
(... | args) // OR
(... ^ args) // XOR
// Comparison operators
(... < args) // Less than
(... > args) // Greater than
// Miscellaneous
(... , args) // Comma
Practical Examples
Example 1: Printing
template<typename... Args>
void print(Args... args) {
(cout << ... << args) << endl;
}
print("x = ", 42, ", y = ", 3.14);
// x = 42, y = 3.14
Example 2: Checking All Values
template<typename... Args>
bool all(Args... args) {
return (... && args);
}
cout << all(true, true, true) << endl; // 1
cout << all(true, false, true) << endl; // 0
Example 3: Adding to a Container
template<typename T, typename... Args>
void push_back_all(vector<T>& vec, Args... args) {
(vec.push_back(args), ...);
}
vector<int> vec;
push_back_all(vec, 1, 2, 3, 4, 5);
// vec = {1, 2, 3, 4, 5}
Example 4: Calling Functions
template<typename... Funcs>
void call_all(Funcs... funcs) {
(funcs(), ...);
}
void f1() { cout << "f1" << endl; }
void f2() { cout << "f2" << endl; }
void f3() { cout << "f3" << endl; }
call_all(f1, f2, f3);
// f1
// f2
// f3
Example 5: Range Checking
template<typename T, typename... Args>
bool in_range(T value, T min, T max, Args... args) {
return ((value >= min && value <= max) || ... ||
(value >= args && value <= args));
}
// Or simplified
template<typename T, typename... Args>
bool contains(T value, Args... args) {
return ((value == args) || ...);
}
cout << contains(3, 1, 2, 3, 4, 5) << endl; // 1
cout << contains(6, 1, 2, 3, 4, 5) << endl; // 0
Example 6: Minimum/Maximum Value
template<typename... Args>
auto min(Args... args) {
return (args < ...); // Incorrect!
}
// Correct implementation
template<typename T>
T min(T value) {
return value;
}
template<typename T, typename... Args>
T min(T first, Args... args) {
T rest = min(args...);
return first < rest ? first : rest;
}
// Or using std::min
template<typename... Args>
auto minimum(Args... args) {
return std::min({args...});
}
cout << minimum(5, 2, 8, 1, 9) << endl; // 1
Comma Operator
template<typename... Args>
void process(Args... args) {
int dummy[] = {(cout << args << " ", 0)...};
}
process(1, 2, 3, 4, 5);
// 1 2 3 4 5
// Or using Fold Expression
template<typename... Args>
void process2(Args... args) {
((cout << args << " "), ...);
}
Common Issues
Issue 1: Empty Pack
// ❌ Empty pack (only some operators allowed)
template<typename... Args>
auto sum(Args... args) {
return (... + args); // Error if pack is empty
}
// ✅ Provide an initial value
template<typename... Args>
auto sum(Args... args) {
return (0 + ... + args); // 0 if pack is empty
}
// Operators that allow empty packs: &&, ||, ,
(... && args) // true
(... || args) // false
(... , args) // void()
Issue 2: Operator Precedence
// ❌ Confusing precedence
template<typename... Args>
auto func(Args... args) {
return (... + args * 2); // Error
}
// ✅ Explicit parentheses
template<typename... Args>
auto func(Args... args) {
return (... + (args * 2));
}
Issue 3: Type Mismatch
// ❌ Type mismatch
auto x = (1 + ... + 3.14); // int + double
// ✅ Explicit type
template<typename T, typename... Args>
T sum(Args... args) {
return (T(0) + ... + T(args));
}
Fold vs Recursion
// Recursion (complex)
template<typename T>
void print(T value) {
cout << value << endl;
}
template<typename T, typename... Args>
void print(T first, Args... args) {
cout << first << " ";
print(args...);
}
// Fold (simple)
template<typename... Args>
void print(Args... args) {
((cout << args << " "), ...);
cout << endl;
}
FAQ
Q1: When should I use Fold Expressions?
A:
- When working with variadic templates
- To handle parameter packs
- To replace recursion
Q2: Are all operators supported?
A: Most binary operators are supported. Unary operators are not.
Q3: What about performance?
A: Performance is similar to recursion, but compile time can be shorter.
Q4: What about empty packs?
A: Only &&, ||, and , are allowed. Other operators require an initial value.
Q5: What about pre-C++17?
A: Use recursive templates.
Q6: Where can I learn more about Fold Expressions?
A:
- “C++17 The Complete Guide”
- cppreference.com
- “Effective Modern C++”
Related Posts: Advanced Variadic Templates, Template Basics, Template Argument Deduction.
## 같이 보면 좋은 글 (내부 링크)
이 주제와 연결되는 다른 글입니다.
- [C++ 가변 인자 템플릿 고급 | pack 확장과 fold 표현식](/blog/cpp-variadic-template-advanced/)
- [C++ Fold Expression 완벽 가이드 | 단항·이항·쉼표 fold·커스텀 연산자 실전](/blog/cpp-series-44-2-fold-expressions/)
- [C++ 템플릿 | "제네릭 프로그래밍" 초보자 가이드](/blog/cpp-template-basics/)
- [C++ 템플릿 인자 추론 | template argument deduction 가이드](/blog/cpp-template-argument-deduction/)
---
---
## 이 글에서 다루는 키워드 (관련 검색어)
C++, fold, variadic, template, parameter-pack 등으로 검색하시면 이 글이 도움이 됩니다.