Open In App

Fold Expressions in C++ 17

Last Updated : 22 Sep, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

Fold expressions in C++17 are a powerful feature that allows you to reduce or “fold” a parameter pack over a binary operator. They were introduced to simplify code that operates on variadic templates and make it more concise and readable.

Syntax

Fold expressions have the following syntax forms:

(pack op ...)
(... op pack)
(pack op ... op init)
(init op ... op pack)

Here, op is any binary operator, pack is an expression containing an unexpanded parameter pack, and init is an expression without an unexpanded parameter pack.

  • Operator (op): This refers to any of 32 different mathematical symbols or signs used for operations like addition (+), subtraction (-), multiplication (*), division (/), and so on. In the context you’ve given, both operands (the things that these operators operate on) must use the same operator.
     
  • Parameter Pack (pack): Think of a parameter pack as a collection or a list of items, but there’s a special condition here. It’s a list that contains variables or expressions that have not been fully determined or expanded yet. It’s like having a placeholder for some values that will be filled in later.
     
  • Expression without Parameter Pack (init): This refers to an expression or a statement that doesn’t involve any placeholder values or incomplete parts. It’s a complete and fully defined piece of code or mathematical operation.

Note: The opening and closing parentheses are a required part of the fold expression.

Types of Fold Expression

Fold expressions come in four types:

1. Unary Right Fold:

(pack op ...)

2. Unary Left Fold:

(... op pack)

3. Binary Right Fold:

(pack op ... op init)

4. Binary Left Fold:

(init op ... op pack)

In a binary fold expression, both operators op must be the same.

Examples:

Let’s look at some practical examples to understand fold expressions better:

1. Unary Left Fold Example

C++




// C++ program to illustrate unary leftfold expression
#include <iostream>
using namespace std;
  
template <typename... Args> bool all(Args... args)
{
    return (... && args);
}
  
int main()
{
    bool b = all(true, true, true, false);
    cout << "Result: " << boolalpha << b << endl;
    return 0;
}


Output

Result: false

In this example, all function checks if all the arguments are true by performing a unary right fold with the logical AND operator &&.

2. Binary Right Fold Example

C++




#include <iostream>
  
template<typename... Args>
int sum(Args&&... args)
{
    return (args + ...); // Performs a binary right fold with addition
}
  
int main()
{
    int result = sum(1, 2, 3, 4);
    std::cout << "Result: " << result << std::endl;
    return 0;
}


Output

Result: 10

Here, the sum function calculates the sum of all its arguments using a binary left fold with the addition operator +.

3. Unary Left Fold with Empty Pack Example

C++




#include <iostream>
  
template<typename... Args>
bool any(Args... args) {
    return (... || args);
}
  
int main() {
    bool b = any(false, false, false);
    std::cout << "Result: " << std::boolalpha << b << std::endl;
    return 0;
}


Output

Result: false

This example demonstrates a unary left fold with an empty pack. The result is false, as the logical OR operator || returns false for an empty pack.

4. Binary Left Fold with Parentheses Example

C++




#include <iostream>
using namespace std;
  
template <typename... Args>
int multiply_and_add(Args... args)
{
    return (1 * ... * args); // Error: operator with
                             // precedence below cast
}
  
int main()
{
    int result = multiply_and_add(1, 2, 3, 4);
    cout << "Result: " << result;
    return 0;
}


In this case, we encounter an error because the binary left-fold expression lacks parentheses around the operator *. To fix this, we need to add parentheses to ensure the correct operator precedence:

C++




#include <iostream>
  
template<typename... Args>
int multiply_and_add(Args... args)
{
    return (1 * ... * (args)); // Corrected with parentheses
}
  
int main()
{
    int result = multiply_and_add(1, 2, 3, 4);
    std::cout << "Result: " << result << std::endl;
    return 0;
}


Output

Result: 24

Ensure that you correctly parenthesize operators when necessary, especially in binary left-fold expressions.

Conclusion

Fold expressions provide a concise and expressive way to work with parameter packs in C++, reducing the need for complex recursive code. They are a valuable addition to modern C++ and can lead to more readable and maintainable code.



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads