I'm experiencing some problems which can be resumed by the following piece of code:
template <typename Key, typename Data, typename fct>
size_t wrapper(const std::pair<Key, Data> & p)
{
return fct(p.first);
}
int main(int argc, char *argv[])
{
size_t val =
wrapper<int, int, dft_hash_fct<int>>(std::pair<int,int>(5,9));
return 0;
}
I'm using clang compiler version 3.4 and this code does not compile with the following error
test-tmp.C:17:5: error: no matching function for call to 'wrapper'
wrapper<int, int, dft_hash_fct<int>>(std::pair<int,int>(5,9));
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
test-tmp.C:9:8: note: candidate template ignored: invalid explicitly-specified argument
for template parameter 'fct'
The idea is to wrap a hash function (the template parameter fct) on std::pair for only taking the first field.
dft_hash_fct is another template defines as follows:
template <typename Key>
size_t dft_hash_fct(const Key & key)
{
return SuperFastHash(key);
}
This generic function works; it has been used in other contexts.
The purpose of all this is to reuse a hash based set (not map) as a map of keys to items of any type. The hash based ser receives a hash function in construction time.
Thanks for your comments (David, Andrey and Kazark)
Edited:
Well, I see, typename fct is a type, so I cannot handle as a pointer function; sorry for the trivia. Unfortunately, I believe that the approach of passing the function as parameter in the wrapper does not work, because the hash set expects a function pointer with the following signature:
size_t (*the_function)(const Key & key);
So, realizing this, thanks to your observations, I changed the code in question to:
template <typename Key, typename Data, size_t (*fct)(const Key & k)>
size_t wrapper(const std::pair<Key, Data> & p)
{
return (*fct)(p.first);
}
int main(int argc, char *argv[])
{
size_t val =
wrapper<int, int, dft_hash_fct<int>>(std::pair<int,int>(5,9));
return 0;
}
that compiles, links and runs. In addition, I put this line:
size_t (*fct)(const std::pair<int, int>&) =
wrapper<int, int, dft_hash_fct<int>>;
cout << (*fct)(std::pair<int, int>(4,6)) << endl;
And that compiles, links ans runs too. So, I can say that the compiler (and of course according to the language) can instantiate the function and handle a function pointer to it.
So, after that I tried to modify my original code, which is a derived class of HAshSet intended for managing pairs hashed by first field.
I declare some as:
template <typename Key, typename Data>
class HashMap : public HashSet<std::pair<Key, Data>>
{
...
HashMap(size_t (*function)(const Key & key))
: HashSet<Key, Data>(wrapper<Key, Data, function>)
{
}
..
};
But the compilation (with std=c++11) fails with the error
./tpl_dynSetHash.H:353:7: error: no matching constructor for initialization of
'HashSet<std::pair<unsigned long, long>>'
: HashSet<std::pair<Key,Data>(
^
testDynSetHash.C:178:8: note: in instantiation of member function
'HashMap<unsigned long, long>::HashMap' requested here
HMap table;
However, if I substitute the call to base constructor by
: HashSet<Key, Data>(wrapper<Key, Data, dft_hash_fct<Key>)
That compiles fine. Thus, I believe that the problem is with the parameter type declaration (but I do not know what is).
>at the end ofwrapper<Key, Data, dft_hash_fct<Key>in your last code block. 2)HashMap(size_t (*function)(const Key & key)) : HashSet<Key, Data>(wrapper<Key, Data, function>)is not possible becausefunctionis not a compile-time constant here (but a function parameter); only compile-time constants (constant expressions) are allowed as non-type template arguments (I'm referring to the third argument ofwrapper<..>).dft_hash_fct<int>as template argument (value known at compile time), but does not work if the function pointer comes through constructor parameter (value not known at compile time). If you want to use run-time function pointers, you have no other choice but to use the approach I described in my answer. I.e. the function pointer must arrive through function parameters, not through template parameters.