Why can't I use boost::adaptor::map_values outside a ranged-based loop?

312 views Asked by At

I want to use boost's boost::adaptor::map_values to construct a vector of all values of a std::map. Take this example code (or try it at Godbolt):

#include <boost/range/adaptors.hpp>
#include <boost/range/adaptor/map.hpp>

std::vector<int> getValueVector(const std::map<int, int> & m)
{
    auto valueRange = boost::adaptors::map_values(m);
    return std::vector<int>(valueRange.begin(), valueRange.end());
}

int main() {
    std::map<int, int> my_map;
    getValueVector(my_map);
}

GCC complains:

error: no match for call to '(const boost::range_detail::map_values_forwarder) (const std::map<int, int>&)'

All examples and all documentation that I can find only ever use boost adaptors inside statements that accept ranges (like range-based for loops or boost::copy), never in statements that need pairs of iterators like std::vector's constructor.

According to GCC, the problem here is that map_values is not applicable to std::map<int, int>. However, this is literally the only example given by the docs, so I'm pretty sure that std::map<int, int> should be okay for map_values.

Whas is amiss here?

P.S.: I know there are a bazillion other ways of elegantly constructing a vector from the values of a map. I want to know why this code does not work. Also, this approach has the added benefit of guaranteed RVO instead of "probably NRVO", which most of the other solutions that I can think of have.

1

There are 1 answers

1
463035818_is_not_an_ai On BEST ANSWER

I am not familiar with ranges, but this might be an answer, so I post it as answer.

At the top they write:

Syntax      Code

Pipe        rng | boost::adaptors::map_values
Function    boost::adaptors::values(rng) 

And indeed when I change your code to this:

#include <boost/range/adaptors.hpp>
#include <boost/range/adaptor/map.hpp>
#include <iostream>

std::vector<int> getValueVector(const std::map<int, int> & m)
{
    auto valueRange = boost::adaptors::values(m);
    return std::vector<int>(valueRange.begin(), valueRange.end());
}

int main() {
    std::map<int, int> my_map{{1,2},{3,4},{5,6}};
    auto v = getValueVector(my_map);
    for (const auto& e : v) std::cout << e << " ";
}

There is the expected output:

2 4 6