事件处理程序模板:未解析的外部
Event handler template: unresolved external
我目前正在从C#过渡到C++,并且不断遇到障碍。我从一个教程中得到了一个事件处理程序系统,并试图将其适应我的需求,但有一个我无法理解的错误:
事件:
#pragma once
class Event
{
protected:
virtual ~Event() {};
};
事件处理程序:
#pragma once
#include "Event.h"
#include "TypeInfo.h"
#include "HandlerFunctionBase.h"
#include <map>
#include <typeindex>
class EventHandler
{
public:
void HandleEvent(const Event*);
template < class T, class EventT >
void RegisterEventFunc(T*, void (T::*memFn)(EventT*));
private:
typedef std::map<std::type_index, HandlerFunctionBase* > Handlers;
Handlers _handlers;
};
[…]
#include "EventHandler.h"
template < class T, class EventT >
void EventHandler::RegisterEventFunc(T* obj, void (T::*memFn)(EventT*))
{
_handlers[std::type_index(typeid(EventT))]=
new MemberFunctionHandler< T, EventT >(obj, memFn);
}
void EventHandler::HandleEvent(const Event* event)
{
Handlers::iterator it = _handlers.find(std::type_index(typeid(*event)));
if(it != _handlers.end())
{
it->second->exec(event);
}
}
HandlerFunctionBase:
#pragma once
#include "Event.h"
class HandlerFunctionBase
{
public:
virtual ~HandlerFunctionBase() {};
void exec(const Event* event) {call(event);}
private:
virtual void call(const Event*) = 0;
};
MemberFunctionHandler:
#pragma once
#include "handlerfunctionbase.h"
template < class T, class EventT >
class MemberFunctionHandler : public HandlerFunctionBase
{
public:
typedef void (T::*MemberFunc)(EventT*);
MemberFunctionHandler(T* instance, MemberFunc memFn) : _instance(instance), _function(memFn) {};
void call(const Event* event)
{
(_instance->*_function)(static_cast< EventT* >(event));
}
private:
T* _instance;
MemberFunc _function;
};
日志处理程序
(我自己的课,首先尝试使用系统)
#pragma once
#include "EventHandler.h"
#include "LogEvent.h"
class LogHandler
{
public:
LogHandler(EventHandler*);
~LogHandler(void);
private:
void Handle(LogEvent*);
};
#[...]
#include "LogHandler.h"
LogHandler::LogHandler(EventHandler *handler)
{
//This line causes the error
handler->RegisterEventFunc<LogHandler, LogEvent>(this, &LogHandler::Handle);
}
LogHandler::~LogHandler(void)
{
}
void LogHandler::Handle(LogEvent* e)
{
}
当我试图编译这个时,我得到了什么:
错误1错误LNK2019:未解析的外部符号"public:void __thiscall EventHandler::RegisterEventFunc(类LogHandler*,void(__thiscallLogHandler::*)(类LogEvent*))"($RegisterEventFunc@VLogHandler@@VLogEvent@@@EventHandler@@QAEXPAVLogHandler@@P81@AEXPAVLogEvent@@@Z@Z)在函数"public:__thiscall LogHandler::LogHandler(类EventHandler*)"中引用(??0LogHandler@@QAE@PAVEventHandler@@@Z) D:\Dropbox\C++\D-Tris \D-Tris \D-Tris\LogHandler.obj D-Tris
RegisterEventFunc是如何解析的?它得到了明确的实施!?
编译器必须知道用于实例化模板的类型才能真正生成代码。但它也为每个翻译单元(一个.cpp文件)独立生成代码。它不会"忽略文件"。
因此,在有了EventHandler::RegisterEventFunc
的定义时,如果它在这个翻译单元之外使用(实例化),它不知道将使用哪些参数来实例化它。
在LogHandler
中,它知道模板EventHandler::RegisterEventFunc
(来自头文件),但由于没有定义,它只是假设在其他地方有RegisterEventFunc<LogHandler, LogEvent>
的实例化,并且不会发出任何错误。
当它链接在一起时,链接器会发现没有人实际实例化RegisterEventFunc<LogHandler, LogEvent>
,因此无法将其链接在一起,并发出您看到的错误。
你能做的是:
1) 将CCD_ 6的定义移动到CCD_。(IMHO,这是通常的解决方案)
2) 或者在EventHandler.cpp
中强制显式实例化,如
template
void EventHandler::RegisterEventFunc<LogHandler, LogEvent>
(LogHandler* obj, void (LogHandler::*memFn)(LogEvent*))
这个"解决方案"打破了封装,增加了许多依赖项,维护起来非常麻烦。
3) 或者使用exported
模板。C++通过关键字export
支持(支持的)模板的使用方式。它只得到了Comeau和ICC的支持(GCC、CLANG和MSVC都不支持这一点),现在它已从标准中删除(在N3690中,在[diff.cpp03.temp]中(附录C.2.7,第1240页),标准上写着:A valid C++ 2003 declaration containing export is ill-formed in this International
Standard.
)。甚至不要尝试,我添加它只是为了完整。
您可能感兴趣的一些相关问题:
如何显式实例化模板函数?
使用导出关键字与模板
为什么模板只能在头文件中实现?(这实际上看起来像是重复的……)
编辑:对于您的另一个问题:您不能通过static_cast
从变量中删除const
限定符。驱散恐慌是潜在的危险,应该避免,但如果你绝对需要,你可以通过const_cast< EventT* >(event)
来做到。
- 如何运行外部程序,向其传递内存地址以读取/写入?
- C++外部程序的输入和输出管道
- 如何调用外部程序并在 C/C++ 中获取多个返回值
- GetAsyncKeyState() - 外部程序会干扰它
- 运行外部程序并获得返回的整数
- 在 c++ 中捕获外部程序的退出代码
- 从外部程序中捕获标准和标准输出 C++.
- 如何通过C 在Mac OS中运行外部程序
- 一个唱片播放器如何使用外部程序在CS:GO中杀人
- Qt:如何通过外部程序打开文件,"open with..."对话框
- C++外部程序集:我的代码中的错误在哪里
- 通过Qt崩溃运行外部程序
- Cpp 中的插件 - 执行外部程序函数
- Qt 执行外部程序
- 停止来自 C++ 代码的外部程序
- 视觉 从 C++ 应用程序执行的外部程序中的 CPU 负载有限
- 如何从服务启动外部程序
- C++暂停外部程序
- 几次调用后,外部程序的执行失败
- 如何在Windows中不显示cmd窗口的情况下运行带参数的外部程序