Множественное определение класса шаблона

У меня есть простой хэш-шаблон таблицы,

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

и класс простого наследования

template <class K, class V, long H(K)>
class HashTable:public HashTableAbs<K, V, H> {}; 

и я хочу специализировать этот шаблон для строки, с моей хэш-функцией по умолчанию

template <class V> 
class HashTable<std::string, V, strSimpleHash>:public HashTableAbs<std::string, V, strSimpleHash> {};
//where strSimpleHash is long strSimpleHash(std::string)

Но когда я пытаюсь скомпилировать этот компилятор, напишите это

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 включает hashtable.h, где определен HashTable) strSimpleHash определяется только в hashtable.h

Есть ли выход? PS извините за мои письменные ошибки. Английский на моем родном языке

Ответ 1

Эта ошибка не связана с шаблонами. Это множественное определение функции. Я думаю, вы определили strSimpleHash в заголовке без использования inline (вы не добавили код, где вы определяете эту функцию).

В ваших комментариях вы попросили использовать HashTable следующим образом:

HashTable<std::string, int> // (ie, without passing the 3rd argument)

Это невозможно. Хотя вы можете указать значение по умолчанию для аргумента шаблона (но не в специализации), например:

template<int n = 0> struct dummy {};
dummy<> obj;

в вашем случае вы не можете этого сделать, потому что общий случай вашего шаблона не принимает только функции типа long(std::string). Однако это можно обойти это, назначив функцию по умолчанию для каждого возможного типа. Обратите внимание, что вы должны использовать указатель на функцию, так как код немного понятнее:

// 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>
{
};

И тогда вы можете использовать его так, как вы хотели, опустив третий параметр шаблона. Обратите внимание, что этот код компилируется на gcc, но не на clang, (На самом деле, я не уверен, какой компилятор прав...)