Reputation: 533
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:
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;
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?
Upvotes: 1
Views: 562
Reputation: 44238
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;
Upvotes: 2