Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

c++

range-v3

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:

#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.

like image 965
notsurewhattodo Avatar asked Dec 31 '25 20:12

notsurewhattodo


1 Answers

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
like image 127
Enlico Avatar answered Jan 03 '26 11:01

Enlico



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!