Search code examples
c++std-rangesc++23

Does std::ranges::to allow converting to a std::map?


In the std::ranges::to paper wg21.link/p1206 ths overview section has the following

//Supports converting associative container to sequence containers
auto f = ranges::to<vector>(m);

However I can't find where the detail of converting to a std::map is descibed in the rest of the paper. I tried range-v3 and Sy Brand's implementation of ranges::to in https://github.com/TartanLlama/ranges and neither of them compiles code converting a range to a std::map. So is this just missing from those libraries or is converting to a std::map not really intended to be allowed?


Solution

  • Does std::ranges::to allow converting to a std::map?

    Yes.

    I tried range-v3 and Sy Brand's implementation of ranges::to in https://github.com/TartanLlama/ranges and neither of them compiles code converting a range to a std::map

    I haven't tried Sy's implementation, and it looks like range-v3's implementation is weirdly broken:

    #include <map>
    #include <vector>
    #include <range/v3/range/conversion.hpp>
    
    int main() {
        std::vector<std::pair<int, int>> v = {{1, 2}, {3, 4}};
    
        // this works (explicit)
        // m1 is a std::map<int, int>
        auto m1 = ranges::to<std::map<int, int>>(v);
    
        // this works (deduced with a pipe)
        // m2 is a std::map<int, int>
        auto m2 = v | ranges::to<std::map>();
    
        // but this does not (deduced, direct call)
        auto m3 = ranges::to<std::map>(v);
    }
    

    The issue is that the class template direct call version in range-v3 for some reason specifically tries to instantiate C<range_value_t<R>> (which would be std::map<std::pair<int, int>> in this case, clearly wrong) even though there is a metafunction here already that does the right thing and would deduce std::map<int, int> (used by the pipe version).

    The ranges::to in the standard library specifies these two to do the same (correct) thing, so this will work in C++23. This is just an easy bug fix in range-v3.