Search code examples
c++dictionaryiteratorreturnc++20

How do I return a map-values iterator from a class function?


The following code compiles fine in C++ 20 (e.g., using https://www.onlinegdb.com/online_c++_compiler) when using auto as a return type of get_map_values_iterator(). However, I want to split this class into implementation and header files, and it seems I cannot use auto as a return type in a class header (which I think I understand why).

So I have tried spelling out the type name of the return value with the help of my IDE, and I came up with

std::ranges::elements_view<std::ranges::ref_view<std::map<int, std::string>>, 1>::_Iterator<true>

However, _Iterator seems to be private, and I am getting errors such as

main.cpp:6:83: error: ‘template struct std::ranges::elements_view > >, 1>::_Iterator’ is private within this context

#include <map>
#include <ranges>
#include <string>

class A {
public:
    // auto // this works
    std::ranges::elements_view<std::ranges::ref_view<std::map<int, std::string>>, 1>::_Iterator<true> // this fails
    get_map_values_iterator() {
        auto values = std::ranges::views::values(my_map);
        auto iterator = values.begin();
        return iterator;
    }
private:
    std::map<int, std::string> my_map;
};

int main() {
    A a;
    a.get_map_values_iterator();
    return 0;
}

I have also figured out that I can implement this function (with auto) in the header file, which is an OKish workaround. But to do it properly, how can I define a class function in an implementation file that returns iterator?


Solution

  • I suppose begin() is not the only iterator that needs to be returned, thus trailing return type -> decltype() is overwording. You can use a deduced iterator type as a user type:

    #include <map>
    #include <ranges>
    #include <string>
    
    class A {
      private:
        std::map<int, std::string> my_map;
    
      public:
        using my_iterator = decltype(std::ranges::views::values(my_map).begin());
    
        my_iterator get_map_begin();
        my_iterator get_map_end();
    };
    
    int main() {
        A a;
        a.get_map_begin();
        a.get_map_end();
        return 0;
    }
    
    A::my_iterator A::get_map_begin() {
        const auto& values = std::ranges::views::values(my_map);
        auto iterator = values.begin();
        return iterator;
    }
    
    A::my_iterator A::get_map_end() {
        const auto& values = std::ranges::views::values(my_map);
        auto iterator = values.end();
        return iterator;
    }