我怎样才能创建基于查找表,以实现在C ++多派遣类型?
-
22-07-2019 - |
题
我试图使一个消息传送系统,其中,任何类从“Messageable”衍生可以接收基于所述函数的handleMessage()是如何过载消息。例如:
class Messageable {
public:
void takeMessage(Message& message) {
this->dispatchMessage(message);
}
protected:
void bindFunction(std::type_info type, /* Need help here */ func) {
m_handlers[type] = func;
}
void dispatchMessage(Message& message) {
m_handlers[typeid(message)](message);
}
private:
std::map<std::type_info, /*Need help here*/ > m_handlers;
};
class TestMessageable : public Messageable {
public:
TestMessageable() {
this->bindFunction(
typeid(VisualMessage),
void (TestMessageable::*handleMessage)(VisualMessage));
this->bindFunction(
typeid(DanceMessage),
void (TestMessageable::*handleMessage)(DanceMessage));
}
protected:
void handleMessage(VisualMessage visualMessage) {
//Do something here with visualMessage
}
void handleMessage(DanceMessage danceMessage) {
//Do something here with danceMessage
}
};
在简而言之我想要的handleMessage的正确版本被称为基于任何给定消息的RTTI值。
如何实现此优选没有某种单片开关/ case语句。
解决方案
您应该看看双调度模式。见信息这里。
您应该能够实现VisualMessage像这样一类:
class VisualMessage : public Message
{
public:
virtual void dispatch(Messageable & inMessageable)
{
inMessageable.handleMessage(*this);
}
};
和然后调用它是这样的:
Message & vMessage = VisualMessage();
Messageable & tMessageable = TestMessageable();
vMessage.dispatch(tMessageable);
它将再调用TestMessageable ::的handleMessage(VisualMessage&visualMessage)
这是因为消息::调度将基于所述VisualMessage类型。然后,当VisualMessage ::调度呼叫inMessageable.handleMessage(*本),它会调用正确的handleMessage因为*这个指针的类型是VisualMessage,不消息。
其他提示
要修复代码:
struct CompareTypeInfo
: std::binary_function<const std::type_info*, const std::type_info*, bool>
{
bool operator()(const std::type_info* a, const std::type_info* b) {
return a->before(*b);
}
};
class Messageable
{
protected:
typedef void (*handlefn)(Messageable *, Message &);
void bindFunction(const std::type_info& type, handlefn func) {
m_handlers[&type] = func;
}
void dispatchMessage(Message& message) {
m_handlers[&typeid(message)](this, message);
}
template <typename S, typename T>
static void handle(Messageable *self, Message &m) {
static_cast<S*>(self)->handleMessage(static_cast<T&>(m));
}
private:
std::map<const std::type_info*, handlefn, CompareTypeInfo> m_handlers;
};
class TestMessageable : public Messageable
{
public:
TestMessageable()
{
this->bindFunction(
typeid(VisualMessage), &Messageable::handle<TestMessageable,VisualMessage>);
this->bindFunction(
typeid(DanceMessage), &Messageable::handle<TestMessageable,DanceMessage>);
}
public:
void handleMessage(VisualMessage visualMessage)
{
//Do something here with visualMessage
}
void handleMessage(DanceMessage danceMessage)
{
//Do something here with danceMessage
}
}
};
那些static_casts可能是“额外的安全”(假设有踢围绕虚函数)dynamic_casts。但设计意味着你知道自己必须是一个指向S,因为否则将不具备此功能注册到它,你知道米必须指向一个T,因为它的typeid已经在DispatchMessage函数检查。如果类正确使用所以不可能发生一个失败的演员,和所有的如果它确实发生了,你所能做的就是调试。
其实我觉得你可以砍下空话多一点通过使bindFunction模板太:
template <typename S, typename T>
void bindFunction(void)
{
m_handlers[&typeid(T)] = handle<S,T>;
}
然后与调用它:
this->bindFunction<TestMessageable,VisualMessage>();
但尽管如此,你可以看到为什么史蒂夫·罗的双调度代码通常是首选...
这是一个老问题,但核文库被设计成提供快速和类型安全消息传递以类似的静脉对这个问题的原意。
充分披露:我的核的共开发商之一
在这种情况下,TestMessageable
类被实现为像这样一个NUClear::Reactor
:
#include <NUClear.h>
// TestMessageable.h
class TestMessageable : NUClear::Reactor {
public:
TestMessageable(NUClear::PowerPlant* powerPlant);
private:
};
// TestMessageable.cpp
#include "TestMessageable.h"
TestMessageable::TestMessageable(NUClear::PowerPlant* powerPlant)
: NUClear::Reactor(powerPlant) {
on<Trigger<VisualMessage>>([this](const VisualMessage& message) {
// Do something with VisualMessage here
// On can also take anything that is callable with a const& VisualMessage.
// Messages are sent using emit.
// If you don't have C++14 NUClear provides std::make_unique
auto classifiedData = std::make_unique<ClassifiedVision>(/* stuff */);
emit(std::move(classifieData));
});
on<Trigger<DanceMessage>>([this](const DanceMessage& message) {
// Do something with DanceMessage here.
});
}
您会发现这类实施中的斯科特迈尔斯更有效的C ++ 并 项目 - 。31 是要与很好解释了。