Fold Expressions (C++17)
Simplify variadic template recursion
The Old Way (C++14)
Before C++17, variadic templates required complex recursive templates.
// C++14: Recursive approach
template<typename T>
auto sum(T value) {
return value;
}
template<typename T, typename... Rest>
auto sum(T first, Rest... rest) {
return first + sum(rest...);
}
// C++17: Fold expression - one line!
template<typename... Args>
auto sum(Args... args) {
return (args + ...); // Unary right fold
}Fold Expression Types
template<typename... Args>
void examples(Args... args) {
// Unary right fold: (args op ...)
// Evaluates: arg1 op (arg2 op (arg3 op ...))
auto sum = (args + ...); // Right associative
// Unary left fold: (... op args)
// Evaluates: ((arg1 op arg2) op arg3) op ...
auto sum_left = (... + args); // Left associative
// Binary right fold: (args op ... op init)
auto sum_init = (args + ... + 0); // With initial value
// Binary left fold: (init op ... op args)
auto sum_left_init = (0 + ... + args);
}
// Practical examples
template<typename... Args>
bool all_true(Args... args) {
return (args && ...); // Logical AND fold
}
template<typename... Args>
bool any_true(Args... args) {
return (args || ...); // Logical OR fold
}
// Usage
all_true(true, true, true); // true
any_true(false, true, false); // truePractical Uses
// Print all arguments
template<typename... Args>
void print_all(const Args&... args) {
(std::cout << ... << args) << std::endl;
}
// Print with separators
template<typename T, typename... Args>
void print(T first, const Args&... args) {
std::cout << first;
((std::cout << ", " << args), ...);
std::cout << std::endl;
}
// Push multiple values to vector
template<typename T, typename... Args>
void push_all(std::vector<T>& vec, Args&&... args) {
(vec.push_back(std::forward<Args>(args)), ...);
}
// Check if all types are same
template<typename T, typename... Rest>
constexpr bool all_same() {
return (std::is_same_v<T, Rest> && ...);
}