patterncppMinor
for_each_cons and for_each_slice, variants of std::for_each working on sliding windows
Viewed 0 times
stdfor_eachslidingworkingfor_each_consvariantswindowsandfor_each_slice
Problem
My goal was to replicate Ruby's
I made two functions,
Outputs:
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());
each_cons and each_slice:(0..5).each_cons(3) {|a, b, c| print a, b, c, "\n"}
012
123
234
345I 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 5And 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
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
- You require
RandomAccessIterators although these should be implementable withForwardIterators as well since you never have to skip an element.
- This will fail for functors with an overloaded or templated
operator()such as those withautoparameters
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.