Fold Expressions

Fold Expressions


C++17 introduced Fold Expressions, a powerful feature that simplifies operations on parameter packs in variadic templates.

Fold expressions allow you to apply an operator to a parameter pack concisely instead of manually expanding it using recursion or initializer_list.

Before C++17, variadic templates required recursion or an initializer_list to process a parameter pack. Let's compare how this was done before and after C++17.

1-Before C++17: Recursive Variadic Template Expansion

#include <iostream>
// Base case (when only one argument remains)
template <typename T>
T sum(T num) {
    return num;
}
// Recursive case (expands parameter pack one by one)
template <typename T, typename... Args>
T sum(T first, Args... rest) {
    return first + sum(rest...);
}
int main() {
    std::cout << sum(1, 2, 3, 4, 5); 
}        

How it expands ?

For sum(1, 2, 3, 4, 5), the compiler expands it like this:

sum(1, 2, 3, 4, 5)
=> 1 + sum(2, 3, 4, 5)
=> 1 + (2 + sum(3, 4, 5))
=> 1 + (2 + (3 + sum(4, 5)))
=> 1 + (2 + (3 + (4 + sum(5))))
=> 1 + (2 + (3 + (4 + 5)))
=> 15        

This works but involves multiple function calls, which can increase compile time and make debugging harder.

2-C++17: Fold Expressions (Simplified Expansion)

With C++17, fold expressions make this much simpler:

#include <iostream>
template <typename... Args>
auto sum(Args... args) {
    return (... + args); 
}
int main() {
    std::cout << sum(1, 2, 3, 4, 5);  
}        

How it expands ?

The fold expression (... + args) expands directly as:

(((1 + 2) + 3) + 4) + 5        

See the difference in https://cppinsights.io/


You can see the number of functions instantiated and the size for the following cases:

1. When we use the variadic templates with five numbers in the sum function
2. When we use the variadic templates with ten numbers in the sum function
3. When we use the Fold Expressions with five numbers in the sum function
4. When we use the Fold Expressions with ten numbers in the sum function

Types of Fold Expressions

There are four types of fold expressions in C++:

  1. Unary Left Fold ( ... op pack )
  2. Unary Right Fold ( pack op ... )
  3. Binary Left Fold ( init op ... op pack )
  4. Binary Right Fold ( pack op ... op init )

1. Unary Left Fold (( ... op pack ))

  • Expands as: ((a op b) op c) op d
  • Evaluates left to right

#include <iostream>
template <typename... Args>
auto sum(Args... args) {
    return (... + args); // Unary left fold
}
int main() {
    std::cout << sum(1, 2, 3, 4) << "\n"; // ((1 + 2) + 3) + 4 = 10
}        


Unary Left Fold

2. Unary Right Fold (( pack op ... ))

  • Expands as: a op (b op (c op d))
  • Evaluates right to left

#include <iostream>
template <typename... Args>
auto subtract(Args... args) {
    return (args - ...); // Unary right fold
}
int main() {
    std::cout << subtract(10, 2, 3) << "\n"; // 10 - (2 - 3) = 10 - 2 + 3 = 11
}        


Unary Right Fold

3. Binary Left Fold (( init op ... op pack ))

  • Expands as: (((init op a) op b) op c) op d
  • Evaluates left to right

#include <iostream>
template <typename... Args>
auto multiply(int init, Args... args) {
    return (init * ... * args); // }
int main() {
    std::cout << multiply(2, 3, 4) << "\n"; // (2 * 3) * 4 = 24
}        


Binary Left Fold

4. Binary Right Fold (( pack op ... op init ))

  • Expands as: a op (b op (c op (d op init)))
  • Evaluates right to left

#include <iostream>
template <typename... Args>
auto divide(int init, Args... args) {
    return (args / ... / init); // Binary right fold
}
int main() {
    std::cout << divide(2, 8, 4) << "\n"; // 8 / (4 / 2) = 8 / 2 = 4
}        


Binary Right Fold


要查看或添加评论,请登录

社区洞察

其他会员也浏览了