Fold Expressions is a new feature of C++ 17, that allows us to create generic algorithms which can operate on any types and any number of inputs. They offer us a flexible, concise, and more efficient way to express what we’re trying to achieve with the code. In this article, we will discuss different types of Fold Expressions in C++17
Prerequisite: Fold Expression in C++
Types of Fold Expression
The fold expression can be classified into 4 types on the basis of the position of the parameter pack, operator and initial values. They are:
- Unary Left Fold
- Unary Right Fold
- Binary Left Fold
- Binary Right Fold
Let’s see each of them in detail.
1. Unary Left Fold Expressions
Unary Left Fold Expressions are those expressions in which the operators have left associativity i.e. while expanding the expression, the leftmost operator and operands will be evaluated first.
Syntax
(... pack op)
where
- pack: Parameter pack.
- op: Operator specifying the operation to be done.
The above expression can also be expanded as:
((pack1 op pack2) op ...) op packN
where N is the number of parameters in the parameter pack.
Example
// C++ Program to Illustrate the Unary Left Fold Expression #include <iostream> using namespace std;
//* Left Associative that is, UNARY LEFT fold template < typename ... Args>
auto diffFromLeft(Args... args)
{ return (... - args);
} // driver code int main()
{ int result = diffFromLeft(2, 3, 5, 7);
cout << result << endl;
return 0;
} |
Output
-13
Explanation
In the above program, the parameters were {2, 3, 5, 7}, and the fold expression used was (… – args) i.e. unary left fold expression. So, the expansion of the expression will be:
(((2 - 3) - 5) - 7)
which is -13.
2. Unary Right Fold Expression
The Unary Right Fold Expressions are opposite to the left fold expression i.e. they are right-associative. It means that the expression is evaluated from Right to Left.
Syntax
(pack op ...)
where
- pack: Parameter pack.
- op: Operator specifying the operation to be done.
The right fold expression will be expanded as:
(pack1 op (... op (packN-1 op packN)))
Example
// C++ Program to Illustrate the #include <iostream> using namespace std;
//* Right Associative that is, UNARY RIGHT FOLD template < typename ... Args>
auto diffFromRight(Args... args)
{ return (args - ...);
} // driver code int main()
{ int result = diffFromRight(2, 3, 5, 7);
cout << result << endl;
return 0;
} |
Output
-3
Explanation
The fold expression is (args – …) which is the right fold expression, so the expansion of the arguments {2, 3, 5, 7} will be different from the previous expression.
(2 - (3 - (5 - 7)))
which is -3.
3. Binary Left Fold Expression
Binary Left Fold Expressions have similar associativity as unary left-fold expressions i.e. left-to-right associativity but there is one more argument which is the initial value.
Syntax
(init op ... op pack)
where
- init: initial value of the given type.
- op: operator specifying the operation to be performed.
- pack: parameter pack
Note: The initial value is useful in cases to avoid errors where the parameter pack does not have any parameters.
Example
// C++ program to illustrate the binary left fold expression #include <iostream> using namespace std;
// function template with parameter pack template < typename ... Args>
auto subtract(Args... args)
{ // Binary left fold
return (0 - ... - args);
} // driver code int main()
{ cout << "Result With Arguments:" << subtract(2, 3, 5, 7)
<< endl;
cout << "Result Without Arguments: " << subtract()
<< endl;
return 0;
} |
Result With Arguments:-17 Result Without Arguments: 0
Explanation
The expression is (0 – … – args) which is a binary left-fold expression. The expansion of the parameters {2, 3, 5, 7} will be similar to the unary left fold expression but there will be additional argument at the start.
((((0 - 2) - 3) - 5) - 7)
which is -17.
4. Binary Right Fold Expression
Binary right-fold expressions have RIGHT to LEFT Associativity and an additional argument – initial value.
Syntax
(args - ... - op)
where
- init: initial value of the given type.
- op: operator specifying the operation to be performed.
- pack: parameter pack
Example
// C++ program to illustrate binary right fold expresssion #include <iostream> using namespace std;
template < typename ... Args>
auto diffFromRight(Args... args)
{ return (args - ... - 24);
} // driver int main()
{ cout << diffFromRight(2, 3, 5, 7) << endl;
return 0;
} |
Output
21
Explanation
The expansion of the expression present in the article (binary right-fold expression) will be:
(2 - (3 - (5 - (7 - 21))))