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); // true

Practical 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> && ...);
}