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:
auto rng = std::equal_range(v.begin(),v.end(),1984);
for(const auto& elem: rng) {
    // ...
}
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:
auto rng = std::equal_range(v.begin(),v.end(),1984);
for(const auto& elem: rng) {
    // ...
}
 
    
     
    
    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.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;
    }
}
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.
