1

I have the following code, it works, but C++20 version does not look much better than C++17 version. My guess issue is that multimap equal_range returns a pair and ranges can not figure out that is a pair of valid iterators.

Is there a way to write this in a shorter nicer way?

#include <iostream>
#include <map>
#include <ranges>

int main() {
    std::multimap<bool,int> oddness{{false,2}, {true,3}, {true,47}, {false,74656}};
    // nice, does not work:
    // oddness.equal_range(true) | std::views::values;
    // works:
    oddness | std::views::values;

    // working code:
    auto odds = oddness.equal_range(true);
    const auto odds_view = std::views::values(std::ranges::subrange(odds.first, odds.second));
    for (const auto& odd : odds_view) {
        std::cout << odd << std::endl;
    }
}
NoSenseEtAl
  • 28,205
  • 28
  • 128
  • 277

1 Answers1

6

The problem is that equal_range returns a pair<It, It>, which is (unfortunately) not itself a range. This is one of the more unfortunate legacy API decisions in my opinion - since we have this excellent name but it does something... less than great.

You used to be able to take a pair<It, It> and easily convert it to a subrange, but that's not necessarily valid and was removed (first in LWG3281 and then the rest in LWG3404). Not all pairs of iterators are actually ranges (several algorithms return two iterators that are not - like minmax_element or mismatch).

But that's okay, we can just write our own explicit one:

struct pair_to_range_t {
    template <typename I>
    friend constexpr auto operator|(std::pair<I, I> const& pr, pair_to_range_t) {
        return std::ranges::subrange(pr.first, pr.second);
    }
};

inline constexpr pair_to_range_t pair_to_range{};

And then you can write:

oddness.equal_range(true) | pair_to_range | std::views::values;
Barry
  • 286,269
  • 29
  • 621
  • 977
  • shame it got removed, but it is safer, I remember that range based for loop had similar standardization change https://stackoverflow.com/questions/6167598/why-was-pair-range-access-removed-from-c11?rq=1 – NoSenseEtAl Aug 06 '21 at 19:05