Почему я получаю ошибку компоновщика с указателем на функцию шаблона? - PullRequest
1 голос
/ 21 января 2011

У меня есть класс EventMgr, который имеет функцию шаблона для регистрации слушателя. Но когда я регистрирую слушателя, компоновщик выдает мне « ошибка LNK2019: неразрешенный внешний символ ».

Код закуски:

class EventMgr {

 template< class T, class EvenT>
 void RegisterListener(T* listener, int EventType, void (T::*MemFunc)(EvenT*) );
}

SoundMgr (слушатель) пытается зарегистрироваться для события:

SoundMgr::SoundMgr(void)
{
  EventManager::GetInstance()->RegisterListener(this, 1, (&SoundMgr::handleBulletFired));
}

Я не уверен, почему он не будет связываться. Почему он не может найти справочные типы?

Ответы [ 2 ]

4 голосов
/ 21 января 2011

Если вы просто объявили шаблон в файле .h, а реализация вместо этого - в файле .cpp, то это ошибка, которую вы получите, потому что компилятор C ++ работает по одному модулю компиляции за раз.Когда компилятор находит ваш код, вызывающий только что объявленную функцию шаблона, он будет предполагать, что конкретная реализация будет выполнена каким-либо другим модулем компиляции (компилятор не может знать, где найти файл .cpp для этой функции... компилятор видит только один .cpp и все включенные .h одновременно).

Если параметры шаблона находятся в хорошо известном списке, вы можете просто запросить все известные вам явные реализации, которые понадобятсядля программы в .cpp.

Например, если у вас есть шаблонная функция

template<typename T>
T foo(T x)
{
   ...
}

, и вы знаете, что вам просто понадобятся int foo(int); и string foo(string);, тогда хорошоиспользуйте только объявление в .h, при условии, что вы также добавите две строки в .cpp, говоря:

template<> int foo(int);
template<> string foo(string);

Делая это, вы сообщаете компилятору о том, какую специализацию строить.Если впоследствии вы в конечном итоге используете другие специализации (например, vector<int> foo(vector<int>)), то вы также должны добавить это явное создание экземпляра в файл .cpp шаблона.

Однако в вашем примере, глядя на код, я предполагаю, что вы незаранее не знаю, какой тип событий будет определен, и поэтому это явное создание экземпляра невозможно.

Другое решение - просто поместить всю реализацию шаблона в файл .h вместо отделения объявления от реализации.Это иногда может быть нетривиальным, потому что требует, чтобы вы раскрыли больше деталей реализации, вероятно, вводя больше зависимостей.

1 голос
/ 21 января 2011

Это, вероятно, означает, что RegisterListener фактически нигде не реализован.Поскольку это шаблонная функция, вы должны реализовать ее в заголовке.

Попробуйте в заголовке следующее.

...