0
#include <iostream>
#include <unordered_map>

using namespace std;

class A{};

int main()
{
    cout<<"Hello World";

    std::unordered_map<A*, int> dic ;
    const A* a;
    auto it = dic.find(a);
    return 0;
}

this code complains "error: invalid conversion from ‘const A*’ to ‘std::unordered_map::key_type’ {aka ‘A*’} [-fpermissive]"

I can not understand it, the cpp refreence https://en.cppreference.com/w/cpp/container/unordered_map/find says I can find a const Key& key, so I think const A* could be used to find A*, but It does not work

Liu Hao
  • 472
  • 4
  • 24
  • 3
    `unordered_map` stores `A*` pointers, not `const A*` pointers. `const A*` doesn't mean "constant pointer to non-constant `A`", it means "non-constant pointer to constant `A*`. When `Key` is an `A*`, a `const Key&` actually means a constant-pointer to non-constant `A`, aka an `A* const`. See also [this question](https://stackoverflow.com/questions/1143262/what-is-the-difference-between-const-int-const-int-const-and-int-const) – Nathan Pierson Jan 09 '22 at 06:03
  • 1
    It's also undefined behavior to use an uninitialized value like `a`, but your question would basically be the same if you did `const A* a = nullptr;` to initialize it. – Nathan Pierson Jan 09 '22 at 06:04
  • Because of the way C++ grammar works, `const int*` is not a const pointer, but rather a pointer to const. What you want is `int* const`. – Aykhan Hagverdili Jan 09 '22 at 06:10
  • I think people are also missing the point here. `std::unordered_map` is capable of transparent comparisons as of C++20 and this code can be made to work just by adding appropriate hash and comparator arguments to the map type: https://gcc.godbolt.org/z/ver5YYjze. Yeah, it's a little more complicated than the default and it's a shame it has to be that way, but for ordinary types, it's sensible to not want a conversion to the key type. – chris Jan 09 '22 at 06:28
  • What is the significance of the apparently-unused `using is_transparent = void;` line? – Nathan Pierson Jan 09 '22 at 07:24
  • @NathanPierson So what do I need to do when I got const A* and need to find it in the map? I could not change the key of the map to `const A*` because of the existing code – Liu Hao Jan 09 '22 at 08:50
  • 1
    @NathanPierson, The method chosen to indicate that a comparator or hash supports the newer transparent capabilities while maintaining backward compatibility was to have said comparator or hash expose an `is_transparent` member that's a type. Which type doesn't matter, so making it an alias for `void` is pretty common. I'm pretty sure I've seen some code use `true_type` to match the name a bit more, but it's an awkward system in the first place. Functions such as `find` will individually check for the member's existence to know whether to allow non-key types. – chris Jan 09 '22 at 09:26

1 Answers1

-4

The problem is that is that when you wrote:

const A* a;

This means a is a pointer to const A which is different from a const pointer to A.

Also, from std::unordered_map::find's documentation, it expects a const Key&. This means find takes the argument as a reference to const Key.

Key in your case is A*.

So in your case, this means that find expects the argument to be A *const and passed by reference.

But you're supplying/giving it an argument a which is const A*. So there is mismatch in types of argument and parameter and hence the error.

Jason
  • 36,170
  • 5
  • 26
  • 60
  • 1
    A bunch of your explanation in this answer are true statements about `std::unordered_map` that don't actually have any relevance to why asker's code isn't behaving as they expect. – Nathan Pierson Jan 09 '22 at 06:17
  • @NathanPierson I have added the correct explanation check it out. – Jason Jan 09 '22 at 06:46