Using Fold with Custom Data Types
Can fold_left()
and fold_right()
be used with custom data types?
Yes, fold_left()
and fold_right()
can be used with custom data types, provided that the custom data type supports the required binary operation.
Requirements for Custom Data Types
- The custom data type must support the operation used in the fold function. This means that if you are using
std::plus<>
, your custom type must have anoperator+
. - The initial value and the elements in the range must be compatible with the binary operation.
Example
Let's create a custom data type Accumulator
that supports the addition operation. We'll use this type with fold_left()
to demonstrate how folding works with custom data types.
#include <algorithm>
#include <iostream>
#include <vector>
struct Accumulator {
int sum;
int count;
Accumulator operator+(int n) const {
return Accumulator{sum + n, count + 1}; }
void log() const {
std::cout << "Count: " << count
<< "\nSum: " << sum << "\n";
}
};
int main() {
std::vector<int> numbers{1, 2, 3, 4, 5};
Accumulator result = std::ranges::fold_left(
numbers, Accumulator{}, std::plus<>());
result.log();
}
Count: 5
Sum: 15
Explanation
- The
Accumulator
struct has two members:sum
andcount
. - We define the
operator+
to allow adding an integer to anAccumulator
object, which updates thesum
andcount
. - The
log()
function is used to print the current state of theAccumulator
.
In the main()
function, we use std::ranges::fold_left()
to combine elements of the numbers
vector using an Accumulator
as the initial value. The custom operator+
ensures that each element of the vector is added to the Accumulator
, updating the sum
and count
accordingly.
Using Different Operations
You can also define other operations for your custom data types. For example, if you have a custom type that represents a complex number, you can define an operator*
for multiplication and use it with fold_left()
.
#include <algorithm>
#include <iostream>
#include <vector>
struct Complex {
double real;
double imag;
Complex operator*(const Complex& other) const {
return Complex{
real * other.real - imag * other.imag,
real * other.imag + imag * other.real
};
}
};
int main() {
std::vector<Complex> numbers{
{1, 2}, {3, 4}, {5, 6}};
Complex initial{1, 0};
Complex result = std::ranges::fold_left(
numbers, initial, std::multiplies<>());
std::cout << "Result: (" << result.real
<< ", " << result.imag << ")";
}
Result: (-85, 20)
In summary, fold_left()
and fold_right()
can be used with custom data types as long as the required operations are defined. This allows for flexible and powerful ways to process collections of custom objects.
C++23 Fold Algorithms
An introduction to the 6 new folding algorithms added in C++23, providing alternatives to std::reduce
and std::accumulate