6

I thought I could have a pointer to a fully-specialized template function, but the following code isn't compiling (MSVC2012)

#include <iostream> #include <string> #include <unordered_map> #include <algorithm> using namespace std; unsigned long hashing_func(string key) { unsigned long hash = 0; for(int i=0; i<key.size(); i++) { hash += (71*hash + key[i]) % 5; } return hash; } bool key_equal_fn2(string t1, string t2) { return t1 == t2; } template<class T> bool key_equal_fn(T t1, T t2) { return t1 == t2; } template <> bool key_equal_fn<string>(string t1, string t2) { return !(t1.compare(t2)); } int main () { unordered_map<string, string>::size_type n = 5; unordered_map<string, string> mymap(n, (const std::hash<string> &)hashing_func, (const std::equal_to<string> &)(key_equal_fn<string>)) ; mymap["paul"] = "jenna"; mymap["frank"] = "ashley"; return 0; } 

The constructor line is returning the following error:

error C2440: 'type cast' : cannot convert from 'bool (__cdecl *)(T,T)' to 'const std::equal_to<_Ty> &'

3
  • cannot convert parameter 3 from 'bool (__cdecl *)(T,T)' to 'const std::equal_to<_Ty> &' Commented Apr 4, 2013 at 10:57
  • 1
    NEVER use C-style casts. Commented Apr 4, 2013 at 11:24
  • There's no conversion. Either (1) supply an object of type equal_to<string> to the constructor of unordered_map<...>, or (2) supply your own type(s) instead of default template argument(s) of unordered_map<...>. Commented Apr 4, 2013 at 11:40

1 Answer 1

15

Both hashing_func and key_equal_fn should be functor objects (and not functions). In addition, their types must be provided to the unordered_map template, that is, the map should have this type:

unordered_map<string, string, hashing_func, key_equal_fn> 

where hashing_func and key_equal_fn are functor classes:

struct hashing_func { unsigned long operator()(const string& key) const { unsigned long hash = 0; for(size_t i=0; i<key.size(); i++) hash += (71*hash + key[i]) % 5; return hash; } }; struct key_equal_fn { bool operator()(const string& t1, const string& t2) const { return !(t1.compare(t2)); } }; 

Then, mymap is defined in this way:

typedef unordered_map<string, string, hashing_func, key_equal_fn> MapType; MapType::size_type n = 5; MapType mymap(n, hashing_func(), key_equal_fn()); 

Alternatively, hashing_func and/or key_equal_fn can be functions but you have to wrapp them into std::function objects. That is,

unsigned long hashing_func(const string& key) { unsigned long hash = 0; for(size_t i=0; i<key.size(); i++) hash += (71*hash + key[i]) % 5; return hash; } bool key_equal_fn(const string& t1, const string& t2){ return !(t1.compare(t2)); } 

and define mymap in this way

typedef unordered_map<string, string, std::function<unsigned long(const string&)>, std::function<bool(const string&, const string&)>> MapType; MapType::size_type n = 5; MapType mymap(n, hashing_func, key_equal_fn); 

If you wish, you can use lambdas and refrain from writing the two funcions or functor classes:

typedef unordered_map<string, string, std::function<unsigned long(const string&)>, std::function<bool(const string&, const string&)>> MapType; MapType mymap(n, [](const string& key) -> unsigned long { unsigned long hash = 0; for(size_t i=0; i<key.size(); i++) hash += (71*hash + key[i]) % 5; return hash; }, [](const string& t1, const string& t2) { return !(t1.compare(t2)); }); 

Finally, my favorite is an all-lambdas solution

auto hashing_func = [](const string& key) -> unsigned long { unsigned long hash = 0; for(size_t i=0; i<key.size(); i++) hash += (71*hash + key[i]) % 5; return hash; }; auto key_equal_fn = [](const string& t1, const string& t2) { return !(t1.compare(t2)); }; typedef unordered_map<string, string, decltype(hashing_func), decltype(key_equal_fn)> MapType; MapType::size_type n = 5; MapType mymap(n, hashing_func, key_equal_fn); 
Sign up to request clarification or add additional context in comments.

2 Comments

I managed to compile my code thanks to your snippets (std::function solved the problem) but now I have a different problem so I'm posting a new question. Thank you!
If using ReSharper, use Alt-Insert to get Generate Code, generate Equality and Hash Function inside the class, and paste the code in to the boilerplate above. Saves typing.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.