为什么我的模板函数指针出现链接器错误?

时间:2011-01-21 19:58:35

标签: c++ templates function-pointers linker-errors

我有一个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 个答案:

答案 0 :(得分:4)

如果您只是在.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 :(得分:1)

这可能意味着RegisterListener实际上并未在任何地方实现。由于它是模板函数,您应该在标题中实现它。

在标题中尝试以下内容。

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