I have a method inside a templated class that creates a hash of a variable. I have specialized its template to int, double and std::string like this
template<>
class Hash<int>
{
public:
unsigned long operator()(const int& d) const noexcept
{
return d * d;
}
};
template<>
class Hash<double>
{
public:
unsigned long operator()(const double& d) const noexcept
{
long intera = floor(d);
long frazionaria = pow(2, 24) * (d - intera);
return intera * frazionaria;
}
};
template<>
class Hash<std::string>
{
public:
unsigned long operator()(const std::string& d) const noexcept
{
unsigned long hash = 5381;
for (unsigned long i = 0; i << d.length(); i )
{
hash = (hash << 5) d[i];
}
return hash;
}
};
I then created a generic version of the same method which takes a template parameter and tries to convert it to std::string and then tries to call operator() on it (which I'd expect would call the specialized template one)
unsigned long operator()(const Data& d) const noexcept
{
std::cout<<"Special hash! ";
void *v = (void *)&d;
size_t j = sizeof(d);
std::string s = "";
for (size_t k = 0; k < j; k )
{
s = (((char *)v)[k]);
}
std::cout<<"Pre-hash: "<<s<<std::endl;
return operator()(s);
}
(it's inside the class declaration while the other 3 are in a different file) So when I call operator() of the Hash class on a int, double or std::string it works fine, but the moment I try to call it on a different class of mine i get this error:
error: cannot convert ‘std::string’ {aka ‘std::__cxx11::basic_string<char>’} to ‘const lasd::BST<int>&’
35 | return operator()(s);
| ^
| |
| std::string {aka std::__cxx11::basic_string<char>}
So it seems to me that it's trying to call operator(BST) again, even though i've passed a string to it. Is there a way I can solve this? I don't care about the hash function being incorrect, I have a uni assignment to do it this way, I only need to understand if it is even possible to call a specialized template function from a normal template one. I also tried using
return operator()<std::string>(s);
as I've seen in some other answers of a similiar question, but I get the following error:
error: expected primary-expression before ‘>’ token
35 | return operator()<std::string>(s);
| ^
https://gcc.godbolt.org/z/9oz8Gf9aM
CodePudding user response:
If I understood correctly, your operator()
needs a Hash
instance to call its specialized operator()
auto operator()(const Data& d) const noexcept
{
// ....
std::string s = "";
return Hash<std::string>{}.operator()(s);
// ^^^^^^^^^^^^^^^^^^^
// OR simply
// return Hash<std::string>{}(s);
}
Update
From the updated post/ error message, you are using the specialization Hash<std::string>
before it has been declared as well as defined. That is at the line:
return Hash<std::string>{}(s);
compiler does not know about the Hash
specialization for std::string
. Hence, the error!
(One way) to fix it, you need to split the declaration and the definition as follows:
template<typename Data> class Hash
{
public:
// declare the operator()
auto operator()(const Data& d) const noexcept;
};
template<> class Hash<int> { /* ...code... */ };
template<> class Hash<double> { /* ...code... */ };
template<> class Hash<std::string> { /* ...code... */ };
// define the operator()
template<typename Data>
auto Hash<Data>::operator()(const Data& d) const noexcept
{
// code!
return Hash<std::string>{}(s);
}