Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

In C++ and range-v3, how to first transform a view and then convert it to a map?

Having any range as an input, how to first convert its elements to tuples and then save them in a std::map with ranges::to?

This code works and creates a vector of tuples:

#include <range/v3/all.hpp>
#include <fmt/format.h>
#include <fmt/ranges.h>

int main() { 
        auto v = ranges::views::iota(3, 10)
                | ranges::views::transform([](auto const &v){ return std::make_tuple(v, v*2); })
                | ranges::to<std::vector>();    
        fmt::print("{}\n", v);
}

Replacing vector by map, I’d expect to receive a map instead (with first elements of the tuples becoming keys and second elements becoming their values), but the code doesn’t compile:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

#include <range/v3/all.hpp>
#include <fmt/format.h>
#include <fmt/ranges.h>

int main() { 
        auto v = ranges::views::iota(3, 10)
                | ranges::views::transform([](auto const &v){ return std::make_tuple(v, v*2); })
                | ranges::to<std::map>();       
        fmt::print("{}\n", v);
}

I get:
test.cpp:11:10: error: invalid operands to binary expression ('invoke_result_t<ranges::views::transform_base_fn, ranges::iota_view<int, int>, (lambda at test.cpp:9:30)>' (aka 'transform_view<ranges::iota_view<int, int>, (lambda at test.cpp:9:30)>') and 'detail::to_container_fn<detail::from_range<std::map>>' (aka 'closure<ranges::detail::from_range<std::map>, ranges::detail::to_container::fn<ranges::detail::from_range<std::map>>>'))

Notes: I didn’t find many examples of using ranges::to<map> in the internet, but in this answer: https://stackoverflow.com/a/74433668 there’s working code where the result of ranges::views::zip is converted to a map. Since zip produces "tuple-like" elements, I expected my code to work too, but apparently it’s not that straightforward.

Compiler is Clang++ v. 15.0.6, ranges is current master.

>Solution :

You need a std::pair, not a std::tuple (working example):

auto m = ranges::views::iota(3, 10)
       | ranges::views::transform([](auto const &v){ return std::make_pair(v, v*2); })
       | ranges::to<std::map>;

After all, while something like this is fine,

std::vector<std::pair<int, int>> v;
std::map<int,int> M(v.begin(), v.end());

something like this is not

std::vector<std::tuple<int, int>> v;
std::map<int,int> M(v.begin(), v.end());

Or, more simply as suggested in a comment,

std::map<int,int> P{{std::pair<int, int>{}}};  // OK
std::map<int,int> T{{std::tuple<int, int>{}}}; // Error
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading