Using overloaded operator[] via an accessor function

梦想的初衷 提交于 2020-01-24 08:46:19

问题


I have an accessor function that returns a const reference to a type (std::map) ... ...

myMap_t const& getMap() const {return paramMap;} 

The type has an overloaded [] operator. What is the syntax to then use the [] operator directly from the getter function in a way like the following, but that actually works.

parameter = contextObj.getMap()[key];

Error message is:

context.cpp:35: error: passing   
  'const std::map<
     std::basic_string<char, std::char_traits<char>, std::allocator<char> >, 
     float, 
     std::less<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, 
     std::allocator<std::pair<
       const std::basic_string<char, std::char_traits<char>, std::allocator<char> >,
       float> > >'
as 'this' argument of 
  '_Tp& std::map<_Key, _Tp, _Compare, _Alloc>::operator[](const _Key&)  
with 
  _Key = std::basic_string<char, std::char_traits<char>, std::allocator<char> >,
  _Tp = float, 
  _Compare = std::less<std::basic_string<char, std::char_traits<char>,  td::allocator<char> > >, 
  _Alloc = std::allocator<std::pair<
    const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, 
    float> >]' 
discards qualifiers

回答1:


The problem is that operator[] in a map is a mutating operation, and you cannot call it on a const reference to a map. The reason that it is mutating is that it must return a reference to a value, and for that, if the key was not already present in the container, it will insert a new default constructed value addressed by that key and return the reference to it.

If you have a const reference, and you want to determine whether an element is present (or access it), you must use std::map<>::find that will return an iterator. If the element is not present the value of the iterator would be m.end()




回答2:


You return the std::map by const reference, but std::map::operator[] is not a const function, because sometimes it needs to alter the map.
To solve this, you should do one of the following:
(A) Use .find instead of []

auto iter = contextObj.getMap().find( key );
if (iter != contextObj.getMap().end())
    param = iter->second;

(B) Return the map as non const (not recommended)
(C) Make a wrapper class (not worth it most of the time)




回答3:


You return a const myMap_t& from your method getMap(). From your error message myMap_t is a typedef for a std::map. Ther operator[] of std::map needs a modifiable object (can't be called on const), since it can insert items into the map (if no item with the specified key exists, it will insert one into the map and return a reference to that one). To solve that problem you have two options:

  • Use contextObj.getMap().find(key) instead of contextObj.getMap()[key] to get an iterator to the element (or to map.end() if it doesn't exist)
  • return myMap_t& (without const) to get a modifiable object on which operator[] can be called



回答4:


context.cpp:35: error: passing   
  'const std::map<
     std::basic_string<char, std::char_traits<char>, std::allocator<char> >, 
     float, 
     std::less<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, 
     std::allocator<std::pair<
       const std::basic_string<char, std::char_traits<char>, std::allocator<char> >,
       float> > >'
as 'this' argument of 
  '_Tp& std::map<_Key, _Tp, _Compare, _Alloc>::operator[](const _Key&)  
with 
  _Key = std::basic_string<char, std::char_traits<char>, std::allocator<char> >,
  _Tp = float, 
  _Compare = std::less<std::basic_string<char, std::char_traits<char>,  td::allocator<char> > >, 
  _Alloc = std::allocator<std::pair<
    const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, 
    float> >' 
discards qualifiers

std::basic_string is the template used to implement std::string, and indeed std::string is simply the instantiation based on char. So substitute that in first:

context.cpp:35: error: passing   
  'const std::map<
     std::string, 
     float, 
     std::less<std::string>, 
     std::allocator<std::pair<const std::string, float> >
  >'
as 'this' argument of 
  '_Tp& std::map<_Key, _Tp, _Compare, _Alloc>::operator[](const _Key&)  
with 
  _Key = std::string,
  _Tp = float, 
  _Compare = std::less<std::string>, 
  _Alloc = std::allocator<std::pair<const std::string> >' 
discards qualifiers

We don't really care about the _Compare (comparison function) and _Alloc (allocator) arguments for our map, since we're just using the defaults; so let's ignore those, and let's also substitute the _Key and _Tp values into the template description:

context.cpp:35: error: passing   
  'const std::map<std::string, float>'
as 'this' argument of 
  'float& std::map<std::string, float>::operator[](const std::string&)  
discards qualifiers

There we go, much simpler. We're using the operator[] of our std::map<std::string, float>, and we're trying to use it on a const std::map<std::string, float> (i.e., that's what we're using as the this argument for the call). This "discards qualifiers", specifically, the const qualifier.

The compiler is telling you that the operator[] of the map does not promise to keep the map const, i.e. it is allowed to change the map. And that is a compiler error, because the code is written with the built-in assertion that the map won't change.

Why would the map change? Well, look at the documentation:

If x matches the key of an element in the container, the function returns a reference to its mapped value.

If x does not match the key of any element in the container, the function inserts a new element with that key and returns a reference to its mapped value. Notice that this always increases the map size by one, even if no mapped value is assigned to the element (the element is constructed using its default constructor).

(Emphasis mine).

Inserting an element is certainly a modification.

Why does it do this? Well, we already have a question for that.



来源:https://stackoverflow.com/questions/10402354/using-overloaded-operator-via-an-accessor-function

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!