I have read some questions that are similar but I don't find the exact thing I am looking for.
In a purely mathematical way a list is defined recursively as: (head, rest)
.
Where head
is the first element in the list and rest
is a list.
So for example (1,2,3,4) is represented as (1, (2,(3,(4,[])))) where []
is the empty list.
Then if we want to iterate over the list we can write a recursive function more or less like this:
iterate(list)
head = list.head
// do stuff and return if head is the empty element
iterate(list.rest)
And if we want to iterate over every 2 elements we do:
pair_iterate(list)
head1 = list.head
head2 = list.rest.head
// do stuff and return if head is the empty element
iterate(list.rest.rest)
I am trying to get that second behaviour in C++.
In C++ 17, folds got introduced, so one can do something like this:
template<typename...types>
auto sum(types...values) {
return (... + values);
}
But let's say we wanted the sum of the products of adjacent parameters, e.g sum(1,2,3,4)
is 1*2 + 3*4
.
In this case we need to "fold twice" to get the the 2 heads to perform the operation and pass the rest of the list. Similar to my pseudocode.
Does anyone have advice on how to get 2 folds in a row?
EDIT: I specifically want to do it with folds, i.e inside the function declaration without having to rely on recursive templated functions.
You can unpack the parameters 2 at a time, like this:
template <typename T1, typename T2, typename ...Ts>
auto sum_products(T1 t1, T2 t2, Ts ...ts)
{
return t1 * t2 + sum_products(ts...);
}
and provide a base case overload for no arguments:
auto sum_products() { return 0; }
and then use it like this:
std::cout << sum_products(1,2,3,4); // prints 14
Here's a demo.
Note that this will only work for an even number of arguments, but you can easily add a single argument overload to handle that case.