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: 15Explanation
- The
Accumulatorstruct has two members:sumandcount. - We define the
operator+to allow adding an integer to anAccumulatorobject, which updates thesumandcount. - 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