1

I'm trying to implement unordered_map with pointer to custom class as key and integer as value.
I thought pointer is just an address, so I wouldn't have to create comparison template for unordered_map, since map would compare between addresses. But I get compile error.
My code is as follow for simple testing. Can anyone help me to fix what have I done wrong?

#include <cstdlib>
#include <unordered_map>
#include <iostream>

using namespace std;

class MyClass{
    public:
        MyClass(int id){m_id = id;};
        void PrintThis(){cout << " This is test " << endl;};
        int m_id;
};


class Test{
    public:
        unordered_map<MyClass* mc, int test> mapTest;

};

int main(){
    MyClass* mc1 = new MyClass(1);
    MyClass* mc2 = new MyClass(2);

    Test* tt1 = new Test();
    tt1->mapTest.insert(make_pair<MyClass*, int>(mc1, 10));
    tt1->mapTest.insert(make_pair<MyClass*, int>(mc2, 20));

    auto search = tt1->find(mc1);
    if(search != tt1->end()) {
        search->first->PrintThis();
    }else{
        cout << "not Found " << endl;
    }

}

Error message is as follow

./main.cpp:17:44: error: wrong number of template arguments (1, should be 5)
         unordered_map<MyClass* mc, int test> mapTest;
                                            ^
In file included from /usr/include/c++/4.8/unordered_map:48:0,
                 from ./main.cpp:2:
/usr/include/c++/4.8/bits/unordered_map.h:97:11: error: provided for 'template<class _Key, class _Tp, class _Hash, class _Pred, class _Alloc> class std::unordered_map'
     class unordered_map : __check_copy_constructible<_Alloc>
           ^
./main.cpp: In function 'int main()':
./main.cpp:26:18: error: request for member 'insert' in 'tt1->Test::mapTest', which is of non-class type 'int'
     tt1->mapTest.insert(make_pair<MyClass*, int>(mc1, 10));

I think I can manage line 26 error, if line 17 gets fixed...

Thanks in advance!

John Doyle
  • 898
  • 2
  • 9
  • 22

2 Answers2

6

I tried your code and found 3 problems:

  1. Declaration of map: it should read std::unordered_map<MyClass*, int>
  2. call of undefined functions (tt1->find/tt1->end, should read tt1->testMap.XXX)
  3. Call of make_pair doesn't require template arguments. The compiler will infer them. This actually causes a problem, as the compiler tries to call make_pair(MyClass *&&, int &&). If I omit the template arguments, it works (make_pair(mc1, 10))

As for point 3:

make_pair is declared as follows in C++11 (C++14 just adds constexpr) (cppreference):

template< class T1, class T2 >
std::pair<V1,V2> make_pair( T1&& t, T2&& u );

For template argument deduction, the follwing rule applies (cf. cppreference)

4) If P is an rvalue reference to a cv-unqualified template parameter (so-called "forwarding reference"), and the corresponding function call argument is an lvalue, the type lvalue reference to A is used in place of A for deduction (Note: this is the basis for the action of std::forward)

(emphasis mine)

So the compiler will infer:

std::make_pair<MyClass *&, int>(MyClass *&, int &&);

where MyClass *& can bind to your actual argument.

If you directly specify the template types, the compiler will stick to

std::make_pair<MyClass *, int>(MyClass *&&, int &&).

As your argument is a lvalue, it cannot be converted to a rvalue-reference, and compilation fails

king_nak
  • 11,313
  • 33
  • 58
  • Thanks a lot! for 1, I modified as suggestion. For 2, was a mistake. tt1->mapTest.find(mc1) is the correct one. For 3, Thanks! :) – John Doyle May 27 '16 at 07:21
2

Your declaration of unordered_map<MyClass* mc, int test> mapTest; is invalid syntax. It should be unordered_map<MyClass*, int> mapTest.

Also remove the template parameters from your make_pair calls and change tt1->find to ttl->mapTest.find() and ttl->end() to ttl->mapTest.end().

Smeeheey
  • 9,906
  • 23
  • 39
  • He is also attempting to access the `std::unordered_map<>` instance through his class variable instead of through the actual member variable. – user2296177 May 27 '16 at 07:15