void.pointer
void.pointer

Reputation: 26315

Is it possible to use range-based for loops with iterator ranges?

Consider the usage with std::multimap, where I am given a range of iterators:

std::unordered_multimap<std::string, MyObject> mymap;

auto& range = mymap.equal_range("some_key");
for (auto& the_pair : range)
{
}

Now, the code above does not compile, but I am using it for demonstration purposes. Is it possible to use range-based for loops with a pair of iterators like this? I don't imagine it is possible directly, so I guess my question is really about whether or not there is an adapter class in STL for this use case. I could probably write my own but this seems like a common case.

Update:

If this is not a common case and STL does not provide such a proxy or adapter for this type of usage, what is required to implement them? I was thinking that I'd need to overload the free functions begin and end and also define an adapter iterator class for std::pair<T,U>. I'm just taking a conceptual stab at it, but please let me know! Thanks in advance everyone.

Upvotes: 5

Views: 3221

Answers (3)

Dumii
Dumii

Reputation: 41

With C++ 20 you can use std::ranges::subrange.

std::unordered_multimap<std::string, MyObject> mymap;

auto range = mymap.equal_range("some_key");
for (auto & [key, value] : std::ranges::subrange(range.first, range.second))
{
}

Upvotes: 1

Rado
Rado

Reputation: 8953

The template-based answer is probably what you are looking for, but i would use a for_each instead with a lambda. It is cleaner and easier to digest.

Upvotes: 3

user4689757
user4689757

Reputation: 106

No, range-based for calls std::begin and std::end. There isn't any overloads for std::pair. At one point, this feature existed in a draft standard but was removed. You can write your own code. Stealing from sellibitze:

template<class Iter>
struct iter_pair_range : std::pair<Iter,Iter> {
    iter_pair_range(std::pair<Iter,Iter> const& x)
    : std::pair<Iter,Iter>(x)
    {}
    Iter begin() const {return this->first;}
    Iter end()   const {return this->second;}
};

template<class Iter>
inline iter_pair_range<Iter> as_range(std::pair<Iter,Iter> const& x)
{ return iter_pair_range<Iter>(x); }

int main() {
    std::unordered_multimap<std::string, MyObject> mymap;

    auto range = mymap.equal_range("some_key");
    for (auto& the_pair : as_range(range))
    {
    }
}

You can look at n2995 from 2009 which talks about adding ranged support to the standard library. Maybe you're better off using Boost.Range.

Upvotes: 9

Related Questions