简体   繁体   中英

Given std::map with pointers to a non-constant class for keys, how to access it via a pointer to const?

There is a map of a type std::map<A*, B*> m that describes correspondence between objects of type A and objects of type B. There is a function int exctractInfo(const A *a) that needs to read some info from an object of type B which corresponds to a given object of type A . This is a semantically constant operation, nothing needs to be changed, we just need to read some info, but the problem is that C++ doesn't allow access to map m via a pointer to const .

Consider the following code:

#include <map>

class A {

};

class B {
    int info_;

public:
    int info() const { return info_; }
};

std::map<A*, B*> m;

int exctractInfo(const A *a) {
    auto it = m.find(a);
    if (it != m.end() && it->second) {
       return it->second->info();
    }
    return -1;
}

int main () {
    return 0;
}

Here's a link to online compiler for this code. I get the following error:

error: invalid conversion from 'const A*' to 'std::map::key_type {aka A*}' [-fpermissive]

Now I see two solutions:

  1. Rewrite the type std::map<A*, B*> as std::map<const A*, B*> , as I have access to the source code, but that is basically a type of a library object, and a lot of code depend on it, so it will have to be changed, thus changing the map type is really undesirable;

  2. Use const cast like this: auto it = m.find(const_cast<A*>(a)); , which also doesn't seem like a good solution, more of a hack.

I don't understand why it doesn't work. If the key is std::string or int , for example, I can access std::map<std::string, B*> via const std::string just fine. So what's wrong with my example? Is there a proper way to handle this situation?

I don't understand why it doesn't work. If the key is std::string or int, for example, I can access std::map via const std::string just fine. So what's wrong with my example?

Because there is a significant difference btw constant pointer to non constant data and non constant pointer to constant data. Your map has first as a key, you try to pass second. So if you are pre C++14 only viable solution would be const_cast I am afraid (beside changing key type of course). If you can use C++14 or later then "transparent comparison" is available as stated in std::map::find() example . For it to work you would need to declare your map like this:

std::map<A*, B*,std::less<>> m;

live example

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM