Iterating between an iterator pair in C++

By gracefu on

C++ comes with a handy dandy footgun named std::multimap [cppreference]. Using a std::multimap, we can store multiple values under the same key, but what do we do when we want to retrieve all values under such a key?

This is one place where std::multimap<T>::equal_range can be used. find can be used as well, but let's focus on equal_range.

std::multimap<int, int> map;

// ... insert elements ...
map.insert({1, 1});
map.insert({4, 2});
map.insert({4, 3});
map.insert({10, 4});

// Print all values whose key is 4
for (
    auto [it, it_end] = map.equal_range(4);
    it != it_end;
    ++it) {
  auto [key, value] = *it;
  std::cout << value << std::endl;
}

That's cool, but it would be great to have an easier way to work with such iterator pairs, like with a range-based for loop. Luckily, it is quite easy to make a loopable class.

template <typename It>
struct IterPair {
  std::pair<It, It> pair;
  explicit IterPair(std::pair<It, It> pair)
    : pair(std::move(pair)) {}

  // This is the magic sauce
  It begin() const { return pair.first; }
  It end() const { return pair.second; }
};

With this, we can beautify our earlier code:

// Get all values whose key is 4
for (auto [key, value] : IterPair(map.equal_range(4))) {
  std::cout << value << std::endl;
}

This class can be made more "do what I mean" with template magic, but for many purposes, this might be enough for you. If so, it might be worth sticking to the simpler class for an easier debugging experience when things go wrong.

Back to home page