Is there a standard implementation of a for_each
that does call with the element and the next one in the range?
For example take the range {0, 1,
You could actually abuse std::unique
or std::adjacent_find
for this: the predicate is called with each consecutive pair in the iterator range, and as long as the predicate always returns false, it won't modify anything or return early.
Disregarding that particular hack, I would implement this as an iterator adapter, not an algorithm. That is, I'd implement a consecutive_tuple_iterator<N>
which would return all tuples of N consecutive items. Then you could use it for things like count_if
and includes
, not just for_each
. (It wouldn't be appropriate for most modifying algorithms, though.)
Not exactly what you want, but take a look at cpplinq.
int numbers[] = {0, 1, 2, 3, 4, 5};
auto pairs = cpplinq::from_array(numbers)
>> cpplinq::pairwise()
>> cpplinq::to_vector(); // yields (0,1), (1,2), (2,3), (3,4), (4,5)
for(auto p : pairs)
f(p.first, p.second);
The simplest thing would be to write it as a generic algorithm, then apply it many times.
template< typename FwdIter, typename Func >
Func for_each_pair( FwdIter iterStart, FwdIter iterEnd, Func func )
{
if( iterStart == iterEnd )
return func;
FwdIter iterNext = iterStart;
++iterNext;
for( ; iterNext != iterEnd; ++iterStart, ++iterNext )
{
func( *iterStart, *iterNext );
}
return func;
}
As I was asked why it returns func (rather than void), this is typical of a for_each because of the fact that
func may "accumulate" some kind of state, but it is the copy we have made into this algorithm that is accumulating it, not the user's original object. We therefore pass them back the modified "func" object.
With C++ 11 and the new iterator helper functions std::next and std::prev for iterators, the second variant of the standard algorithm std::transform can be used to iterate over adjacent elements.
Here is an example that generates a list of adjacent pairs from a list:
std::vector<int> nums{3, 4, 2, 9, 15, 267};
std::vector<std::pair<int,int>> num_pairs;
if (!nums.empty()) {
std::transform(
std::begin(nums), std::prev(std::end(nums)),
std::next(std::begin(nums)),
std::back_inserter(num_pairs),
std::make_pair<
decltype(nums)::const_reference,
decltype(nums)::const_reference
>
);
}