Reputation: 30038
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;
}
}
Upvotes: 1
Views: 610
Reputation: 303107
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;
Upvotes: 6