2
\$\begingroup\$

I recently had to repeatedly iterate over an array but increment the index to start from each time. Since this is quite cumbersome in comparison to a normal for loop I made a small template function that does this for me:

#include <algorithm>
#include <iostream>
template<typename TSize, typename TFunc>
void for_start(const TSize start, const TSize size, TFunc&& fn)
{
 for(TSize c{}, i{c + start}; c < size; ++c, ++i)
 {
 if(i >= size)
 i = 0;
 fn(i);
 }
}
template<typename TRAIter, typename TFunc>
void for_start(TRAIter start, TRAIter begin, TRAIter end, TFunc&& fn)
{
 for(TRAIter c{begin}, i{c + std::distance(begin, start)}; c != end; ++i, ++c)
 {
 if(i == end)
 i = begin;
 fn(i);
 }
}
// usage
int main()
{
 const unsigned ARR_SIZE{10};
 int arr[ARR_SIZE]{
 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
 };
 for_start(5u, ARR_SIZE, [arr](unsigned i)
 {
 std::cout << arr[i] << ' ';
 });
 std::cout << '\n';
 for_start(std::begin(arr) + 5, std::begin(arr), std::end(arr), [](const int* i)
 {
 std::cout << *i << ' ';
 });
}
// prints:
// 5 6 7 8 9 0 1 2 3 4 
// 5 6 7 8 9 0 1 2 3 4 

I'd like to get some feedback on things like usability (function name, order of parameters) and reuseability. Note that I'd like to use this function with signed & unsigned integers.

asked Jan 16, 2019 at 19:15
\$\endgroup\$
2
  • \$\begingroup\$ If you weren't constrained to C++11, I'd have suggested you look into std::range, which has been voted in to C++20. \$\endgroup\$ Commented Jan 16, 2019 at 19:17
  • \$\begingroup\$ @TobySpeight, this is not my birthday, but thank you for the gift. Though googling for it didn't yield anything useful yet. \$\endgroup\$ Commented Jan 16, 2019 at 19:18

1 Answer 1

5
\$\begingroup\$
  • There is no reason to initialize i as {c + std::distance(begin, start)}. Upon such initialization you are guaranteed that i == start. A much simpler i{start} suffices.

  • Testing for i == size, or i == end inside the loop, as well as tracking two iterators, feels wasteful. Consider splitting the loop into two, e.g:

     for (i = start; i != end; ++i) {
     fn(i);
     }
     for (i = begin; i != start; ++i) {
     fn(i);
     }
    
  • I am not sure that for_start is a good name. I am also not sure what name would be good. iterate_rotated perhaps?

answered Jan 16, 2019 at 20:45
\$\endgroup\$
1
  • \$\begingroup\$ The idea to use 2 seperate loops didn't even cross my mind... Thank you! \$\endgroup\$ Commented Jan 17, 2019 at 16:02

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.