HiveBrain v1.2.0
Get Started
← Back to all entries
patterncppMinor

for_each_cons and for_each_slice, variants of std::for_each working on sliding windows

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
stdfor_eachslidingworkingfor_each_consvariantswindowsandfor_each_slice

Problem

My goal was to replicate Ruby's each_cons and each_slice:

(0..5).each_cons(3) {|a, b, c| print a, b, c, "\n"}
012
123
234
345


I made two functions, for_each_cons, and for_each_slice. They work similarly to their Ruby counterparts, except the slice is always passed to separate arguments. The slice size is deducted from the passed function's number of arguments.

const std::vector vec = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
for_each_cons(vec, [](int a, int b, int c){
    printf("%d %d %d\n", a, b, c);
});

for_each_slice(vec, [](int a, int b, int c){
    printf("%d %d %d\n", a, b, c);
});


Outputs:

0 1 2
1 2 3
2 3 4
3 4 5

0 1 2
3 4 5


And here's the implementation. For simple code it seems to generate similar assembly to manual implementations, although it's largely because it requires random access iterators.

```
#include

namespace detail
{
template
struct function_params
: public function_params
{};

template // for lambdas
struct function_params {
static constexpr int n_args = sizeof...(Args);
};

template // for mutable lambdas
struct function_params {
static constexpr int n_args = sizeof...(Args);
};

template // for function pointers
struct function_params {
static constexpr int n_args = sizeof...(Args);
};

template::n_args, std::size_t... I>
void for_each_cons_impl(It first, It last, Fun f, std::index_sequence) {
for(auto it = first; it + N - 1 ::n_args, typename Indices = std::make_index_sequence>
void for_each_cons(It first, It last, Fun f) {
for_each_cons_impl(first, last, f, Indices());
}

template::n_args, std::size_t... I>
void for_each_slice_impl(It first, It last, Fun f, std::index_sequence) {
for(auto it = first; it + N - 1 ::n_args, typename Indices = std::make_index_sequence>
void for_each_slice(It first, It last, Fun f) {
for_each_slice_impl(first, last, f, Indices());

Solution

The two main issues I see are that

  • You require RandomAccessIterators although these should be implementable with ForwardIterators as well since you never have to skip an element.



  • This will fail for functors with an overloaded or templated operator() such as those with auto parameters



Also, what happens if the range's length isn't divisible by the step size in the second case?

As 2 isn't really possible to solve since in the overloaded case there may be multiple valid values for n_args you could allow the user to pass the number of arguments as a first parameter. You could then default that value to 0 (which is never valid) and infer the number of parameters as you currently do if it is set to 0.

Context

StackExchange Code Review Q#91986, answer score: 2

Revisions (0)

No revisions yet.