Reputation: 1508
I have a simple hash table template,
template <class K, class V, long H(K)>
class HashTableAbs{/* .... */}
//where K is key type, V is value type, H gives hash code for K value
and simple inheritor class
template <class K, class V, long H(K)>
class HashTable:public HashTableAbs<K, V, H> {};
and i want to specialize this template for string, with my default hash function
template <class V>
class HashTable<std::string, V, strSimpleHash>:public HashTableAbs<std::string, V, strSimpleHash> {};
//where strSimpleHash is long strSimpleHash(std::string)
But when i trying to compile this compiler write this
test.o: In function `strSimpleHash(std::string)':
test.cpp:(.text+0x0): multiple definition of `strSimpleHash(std::string)'
/tmp/main-i7yPhc.o:main.cc:(.text+0x0): first defined here
clang: error: linker command failed with exit code 1 (use -v to see invocation)
(test includes hashtable.h where HashTable is defined) strSimpleHash is defined only in hashtable.h
Is there way out? PS sorry for my writing mistakes. English in not my native language
Upvotes: 0
Views: 1431
Reputation: 9388
This error is not really related to templates. It is a multiple definition of a function. I guess you have defined strSimpleHash
in a header without using inline
(you didn't add the code where you define this function).
You asked in your comments a way to use HashTable
like the following:
HashTable<std::string, int> // (ie, without passing the 3rd argument)
This is not directly possible. Althought you can specify a default value for a template argument (but not in a specialization), for example:
template<int n = 0> struct dummy {};
dummy<> obj;
in your case you cannot do that, because the general case of your template does not accept only functions of type long(std::string)
.
However, it is possible to workaround this by assigning a default function for each possible type. Note that you should use pointer-to-function, as the code is a little clearer:
// A C++03-style template typedef
template<typename K>
struct HashFunc
{
typedef long (*type)(K);
};
// The default value. Defined only for some cases,
// compile error for not handled cases
template<typename K>
struct DefaultHash;
template<>
struct DefaultHash<std::string>
{
// Static constant pointer-to-function, pointing to the hash func.
static constexpr HashFunc<std::string>::type func = &strSimpleHash;
};
// The HashTable class
template <class K, class V, typename HashFunc<K>::type H = DefaultHash<K>::func>
class HashTable
{
};
template <class V>
class HashTable<std::string, V, strSimpleHash>
{
};
And then you can use it as you wanted, omitting the third template parameter. Note that this code compiles on gcc, but not on clang. (Actually, I'm not sure about which compiler is right...)
Upvotes: 3