0

I'm trying to implement a wrapper class over unordered_map.

#include <iostream>
#include <unordered_map>
using namespace std;

template< class Key > class HashFn
{
  public:
    size_t operator() (Key & inKey);
};

template<> size_t HashFn< string >::operator()(string & inKey)
{
    return std::hash<string>{}(inKey);
}

template< class Key, class Val, class Hash = HashFn< Key > > class unordered_map_wrapper
{
    private:
      unordered_map<Key, Val, Hash> * mTable;
    public:
      unordered_map_wrapper( );
      bool insert( pair<Key, Val> & inPair );
};


template< class Key, class Val, class Hash > unordered_map_wrapper< Key, Val, Hash >::unordered_map_wrapper( )
{
  mTable = new unordered_map< Key, Val, Hash >( );
}


template< class Key, class Val, class Hash > bool unordered_map_wrapper< Key, Val, Hash >::insert( pair<Key, Val> & inPair )
{
  //internal implementation
  return NULL;
}


int main() {
    unordered_map_wrapper< string,unsigned > h();       
    h.insert(std::make_pair< string,unsigned >( "One", 1 ));
    return 0;
}

Here hash Function is templated on templated class Key. The identifiers for unordered_map_wrapper templated class are Key, Val and Hash = HashFn< Key >.

Here, we are using a template specialisation of the string as default and passing HashFn class(template class) as the default argument. When we are inserting it as a string, we are using an overloaded operator() as specialisation.

If HashFn class is not templated, instead if we are using only string as a concrete implementation without templates, it works.

But when we are using the template, getting a compilation error:

test.cpp: In function ‘int main()’:
test.cpp:40:7: error: request for member ‘insert’ in ‘h’, which is of non-class type ‘unordered_map_wrapper<std::__cxx11::basic_string<char>, unsigned int>()’
     h.insert(std::make_pair< string,unsigned >( "One", 1 ));
       ^~~~~~

It seems like we are not able to detect the template specialisation for the string in hashFn class.

This issue appears only when h.insert() is called or are we missing something.

Please suggest a way out. Thanks in advance!

Foobar-naut
  • 123
  • 1
  • 1
  • 9
  • The parameter of your `insert` method is `const bool&`, not a pair of `key_type` and `mapped_type` – KABoissonneault Mar 07 '17 at 16:40
  • 2
    Look up _most vexing parse_, remove the `()` after `h` in your declaration (you're declaring `h` as a function that takes no parameters and returns an `unordered_map_wrapper`), then delete this question as a duplicate. – 1201ProgramAlarm Mar 07 '17 at 16:43
  • This is not working also: `unordered_map_wrapper< string,unsigned > h;` I have also tried using `new` but the same compilation error is coming! – Foobar-naut Mar 07 '17 at 17:34
  • The relevant error: `/usr/include/c++/6/bits/hashtable_policy.h:85:34: error: no match for call to ‘(const HashFn >) (const std::__cxx11::basic_string&)’ noexcept(declval()(declval()))> ~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~ prog.cpp:11:19: note: candidate: size_t HashFn::operator()(Key&) [with Key = std::__cxx11::basic_string; size_t = long unsigned int] template<> size_t HashFn< string >::operator()(string & inKey)` – Foobar-naut Mar 07 '17 at 17:47
  • This error shows that it is not able to match type with the operator() implementation for template specialisation of string! – Foobar-naut Mar 07 '17 at 17:49

1 Answers1

1

You should really begin to add const in your code. But lets start in the beginning:

1. Most vexing parse

test.cpp:41:5: error: base of member reference is a function; perhaps you meant to call it with no arguments?

refers to

unordered_map_wrapper< string,unsigned > h();

This line can be read as a function declaration of h, taking no argument, returning an unordered_map_wrapper<string, unsigned>. Or it could be a declaration of a variable h, with default constructor and type unordered_map_wrapper<string, unsigned>. The standard says, it is the first.

Either you need to use no brackets, or curly braces. Check for most vexing parse.

2. Use const(1)

test.cpp:41:14: error: non-const lvalue reference to type 'pair<...>' cannot bind to a temporary of type 'pair<...>'
[...]

refers to

bool insert( pair<Key, Val> & inPair );

Your insert takes a reference to a pair<Key, Val>, in your case you pass an rvlaue, so you can't bind it. You should either use a universal reference or a const reference. So, the easiest fix is to use

bool insert( const pair<Key, Val> & inPair );

3. Use const (2)

/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/6.3.1/../../../../include/c++/6.3.1/bits/hashtable_policy.h:85:11: error: no matching function for
      call to object of type 'const HashFn<std::__cxx11::basic_string<char> >'
[...]

refers to your hash function - it cannot hash your Key.

This is again due to missing consts. Your hash function should have the signature

size_t operator() (const Key & inKey) const;

Conclusion

Your final code should look like this:

#include <iostream>
#include <unordered_map>
using namespace std;

template <class Key> class HashFn {
public:
  size_t operator()(const Key &inKey) const;
};

template <> size_t HashFn<string>::operator()(const string &inKey) const {
  return std::hash<string>{}(inKey);
}

template <class Key, class Val, class Hash = HashFn<Key>>
class unordered_map_wrapper {
private:
  unordered_map<Key, Val, Hash> *mTable;

public:
  unordered_map_wrapper();
  bool insert(const pair<Key, Val> &inPair);
};

template <class Key, class Val, class Hash>
unordered_map_wrapper<Key, Val, Hash>::unordered_map_wrapper() {
  mTable = new unordered_map<Key, Val, Hash>();
}

template <class Key, class Val, class Hash>
bool unordered_map_wrapper<Key, Val, Hash>::insert(
    const pair<Key, Val> &inPair) {
  return mTable->insert(inPair).second;
}

int main() {
  unordered_map_wrapper<string, unsigned> h{};
  h.insert(std::make_pair<string, unsigned>("One", 1));
  return 0;
}

I didn't check whether you now use const whereever you can, but you should really start doing this.

overseas
  • 1,711
  • 1
  • 18
  • 30
  • Thanks @overseas for helping out! This code is compiling fine. But failing to cout anything at template specialisation of string. Maybe this is not getting accepted as function and default Hash function of unordered_map is working instead. Do we need to use Hasher Function? Or use the [constructor of HashFn](http://stackoverflow.com/questions/7222143/unordered-map-hash-function-c)? `template< class Key, class Val, class Hash > unordered_map_wrapper< Key, Val, Hash >::unordered_map_wrapper( ) { mTable = new unordered_map< Key, Val, Hash >(1, HashFn()); }` 1 is size_type_Buskets – Foobar-naut Mar 09 '17 at 18:43
  • What do you mean with "But failing to cout anything at template specialisation of string"? – overseas Mar 09 '17 at 19:04
  • Like this: `template <> size_t HashFunction::operator()(const string &inKey) const { cout << "at operator()" << endl; return std::hash{}(inKey); }` – Foobar-naut Mar 09 '17 at 19:32
  • I think this is just because you didn't implement insert yet (I just copied this from your implementation). So you will need to implement this function (see above). Of course using universal references and just forwarding the insert would be better, but I used your function declarations. – overseas Mar 09 '17 at 20:33
  • Using a non-default constructor does not make sense here as you just use the default constructor which is fine. – overseas Mar 09 '17 at 20:36