0
#include <iostream>
#include <vector>
#include <string>
#include <map>
#include <unordered_map>
#include <any>
using namespace std;

using MapAny = std::unordered_map<string, std::any>;


int main()
{
    vector<MapAny> params;
    params.push_back({ {"a", 1}, {"b", 2} });
    params.push_back({ {"a", 4}, {"b", 6} });
    params.push_back({ {"a", 10}, {"b", 15} });

    // I want to const-reference loop over params
    for (int i=0; i<params.size(); i++) {
        auto param = params[i]; // slow copy, not refernece 
        //auto& param = params[i]; // work but I want const
        //const auto& param = params[i]; // compile error        

        cout << any_cast<int>(param["a"]) << " " << any_cast<int>(param["b"]) << "\n";
    }
    
    // doesn't compile
    for (const auto& param : params) {
        //cout << any_cast<int>(param["a"]) << " " << any_cast<int>(param["b"]) << "\n";
    }

    // also doesn't compile
    for (auto it=params.cbegin(); it!=params.cend(); it++) {
        //cout << any_cast<int>((*it)["a"])) << " " << any_cast<int>(param["b"]) << "\n";
    }

    return 0;
}

I have a vector containing map objects. I wish to loop over each map as const reference. However, using const auto& doesn't work and it gives error at the [] operator.

How can I fix the above code to loop the vector by const-reference ?

Edit: the compiler error if I use const auto& param = params[i] is:

test_auto.cpp: In function ‘int main()’:
test_auto.cpp:25:40: error: passing ‘const std::unordered_map<std::__cxx11::basic_string<char>, std::any>’ as ‘this’ argument discards qualifiers [-fpermissive]
   25 |         cout << any_cast<int>(param["a"]) << " " << any_cast<int>(param["b"]) << "\n";
      |                                        ^
In file included from /usr/include/c++/10/unordered_map:47,
                 from test_auto.cpp:5:
/usr/include/c++/10/bits/unordered_map.h:987:7: note:   in call to ‘std::unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::mapped_type& std::unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::operator[](std::unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::key_type&&) [with _Key = std::__cxx11::basic_string<char>; _Tp = std::any; _Hash = std::hash<std::__cxx11::basic_string<char> >; _Pred = std::equal_to<std::__cxx11::basic_string<char> >; _Alloc = std::allocator<std::pair<const std::__cxx11::basic_string<char>, std::any> >; std::unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::mapped_type = std::any; std::unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::key_type = std::__cxx11::basic_string<char>]’
  987 |       operator[](key_type&& __k)
      |       ^~~~~~~~
test_auto.cpp:25:76: error: passing ‘const std::unordered_map<std::__cxx11::basic_string<char>, std::any>’ as ‘this’ argument discards qualifiers [-fpermissive]
   25 |         cout << any_cast<int>(param["a"]) << " " << any_cast<int>(param["b"]) << "\n";
      |                                                                            ^
In file included from /usr/include/c++/10/unordered_map:47,
                 from test_auto.cpp:5:
/usr/include/c++/10/bits/unordered_map.h:987:7: note:   in call to ‘std::unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::mapped_type& std::unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::operator[](std::unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::key_type&&) [with _Key = std::__cxx11::basic_string<char>; _Tp = std::any; _Hash = std::hash<std::__cxx11::basic_string<char> >; _Pred = std::equal_to<std::__cxx11::basic_string<char> >; _Alloc = std::allocator<std::pair<const std::__cxx11::basic_string<char>, std::any> >; std::unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::mapped_type = std::any; std::unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::key_type = std::__cxx11::basic_string<char>]’
  987 |       operator[](key_type&& __k)
      |       ^~~~~~~~
Huy Le
  • 1,439
  • 4
  • 19
  • 8
    You can't access a const map using `operator[]`. Use `find` or similar facilities. – tkausl Mar 24 '22 at 09:38
  • the question would be better if you would include the compiler error message. – 463035818_is_not_an_ai Mar 24 '22 at 09:38
  • Oh, I never noticed std::map doesn't have a const reference version of operator []. Should I delete the question or leave it for reference? – Huy Le Mar 24 '22 at 09:40
  • Also, is there any reason operator [] doesn't have a const reference version? I think the answer should explain that. – Huy Le Mar 24 '22 at 09:42
  • 3
    @HuyLe The problem is not with the non-const-reference version of `operator[]`. The problem is that `operator[]` is a non-const member function. It must be, since it eventually needs to insert a new element into the map. – Daniel Langr Mar 24 '22 at 09:43
  • `param.find("a")` and `param.find("b")` should help. Also consider `std::variant` instead of `std::any` as you cannot do much with a `std::any`, not even print it. – The Coding Fox Mar 24 '22 at 09:45
  • In order to make a "truly const" version of `operator[]`, the compiler would have to be able to prove at compile time that the key is already present in the map. – molbdnilo Mar 24 '22 at 10:08

0 Answers0