Daiver
Daiver

Reputation: 1508

template class multiple definition

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

Answers (1)

Synxis
Synxis

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

Related Questions