If I have range (pair of 2 iterators) is there a way to write \"for each\" loop for that uses range, not a raw array or container.
Something like this:
As per Why was pair range access removed from C++11? you can use an adaptor e.g. the as_range
at the accepted answer, boost::make_iterator_range, or write your own:
template<typename It> struct range {
It begin_, end_;
It begin() const { return begin_; }
It end() const { return end_; }
};
template<typename It> range<It> as_range(const std::pair<It, It> &p) {
return {p.first, p.second};
}
auto rng = std::equal_range(v.begin(),v.end(),1984);
for(const auto& elem: as_range(rng))
...
The reason this isn't applicable in general is that per Alastair Meredith's paper, of the algorithms,
mismatch
and partition_copy
return a pair of iterators from different ranges;minmax
returns a pair of objects that may not be iterators at all, and if they are there's no guarantee they form a range;minmax_element
can return a range, but it can also return a reversed range (e.g. on a reverse-sorted range minmax_element
will return {prev(last), first}
;equal_range
is guaranteed to return a range.What std::equal_range
returns is simply a std::pair. The standard doesn't cover any method to iterate over such things.
What you may want to read is Alexandrescu's "Iterators must go" presentation. Here is the video. An excellent read on a more elegant way to iterate containers using Ranges.
Ranges are implemented in his Loki library.
I don't think it will work like that out of the box as equal_range
returns a pair of iterators while, the for cycle over range according to documentation are:
The begin_expr and end_expr are defined to be either:
If (__range) is an array, then (__range) and (__range + __bound), where __bound is the array bound
If (__range) is a class and has either a begin or end member (or both), then begin_expr is __range.begin() and end_expr is __range.end();
Otherwise, begin(__range) and end(__range), which are found based on argument-dependent lookup rules with std as an associated namespace.
I would say you may define begin
and end
functions that take the pair of iterators and return first and second one resepectively.
#include <vector>
#include <algorithm>
#include <iostream>
template <typename I>
struct range_adapter {
std::pair<I, I> p;
range_adapter(const std::pair<I, I> &p) : p(p) {}
I begin() const { return p.first; }
I end() const { return p.second; }
};
template <typename I>
range_adapter<I> in_range(const std::pair<I, I> &p)
{
return range_adapter<I>(p);
}
int main()
{
std::vector<int> data { 1, 2, 2, 3, 3, 3, 4 };
auto r = std::equal_range(data.begin(), data.end(), 2);
for (const auto &elem : in_range(r))
{
std::cout << elem << std::endl;
}
}