for_each_cons and for_each_slice, variants of std::for_each working on sliding windows 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&lt;int&gt; 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 &lt;utility&gt;

namespace detail
{
    template &lt;typename Fun&gt;
    struct function_params
        : public function_params&lt;decltype(&amp;Fun::operator())&gt;
    {};

    template &lt;typename Class, typename Ret, typename... Args&gt; // for lambdas
    struct function_params&lt;Ret(Class::*)(Args...) const&gt; {
        static constexpr int n_args = sizeof...(Args);
    };

    template &lt;typename Class, typename Ret, typename... Args&gt; // for mutable lambdas
    struct function_params&lt;Ret(Class::*)(Args...)&gt; {
        static constexpr int n_args = sizeof...(Args);
    };

    template &lt;typename Ret, typename... Args&gt; // for function pointers
    struct function_params&lt;Ret(*)(Args...)&gt; {
        static constexpr int n_args = sizeof...(Args);
    };

    template&lt;typename It, typename Fun, int N = function_params&lt;Fun&gt;::n_args, std::size_t... I&gt;
    void for_each_cons_impl(It first, It last, Fun f, std::index_sequence&lt;I...&gt;) {
        for(auto it = first; it + N - 1 &lt; last; ++it)
            f(*(it + I)...);
    }

    template&lt;typename It, typename Fun, int N = function_params&lt;Fun&gt;::n_args, typename Indices = std::make_index_sequence&lt;N&gt;&gt;
    void for_each_cons(It first, It last, Fun f) {
        for_each_cons_impl(first, last, f, Indices());    
    }

    template&lt;typename It, typename Fun, int N = function_params&lt;Fun&gt;::n_args, std::size_t... I&gt;
    void for_each_slice_impl(It first, It last, Fun f, std::index_sequence&lt;I...&gt;) {
        for(auto it = first; it + N - 1 &lt; last; it += N)
            f(*(it + I)...);
    }

    template&lt;typename It, typename Fun, int N = function_params&lt;Fun&gt;::n_args, typename Indices = std::make_index_sequence&lt;N&gt;&gt;
    void for_each_slice(It first, It last, Fun f) {
        for_each_slice_impl(first, last, f, Indices());    
    }
}

template&lt;typename It, typename Fun&gt;
void for_each_cons(It first, It last, Fun f) {
    detail::for_each_cons(first, last, f);
}

template&lt;typename Rng, typename Fun&gt;
void for_each_cons(Rng &amp;&amp;rng, Fun f) {
    for_each_cons(rng.begin(), rng.end(), f);
}

template&lt;typename It, typename Fun&gt;
void for_each_slice(It first, It last, Fun f) {
    detail::for_each_slice(first, last, f);
}

template&lt;typename Rng, typename Fun&gt;
void for_each_slice(Rng &amp;&amp;rng, Fun f) {
    detail::for_each_slice(rng.begin(), rng.end(), f);
}


Any hints and criticism are welcome.
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.