[英]How can I create a type based lookup table in order to implement multiple-dispatch in C++?
我正在嘗試創建一個消息傳遞系統,其中任何派生自“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
}
};
簡而言之,我希望根據任何給定消息的RTTI值調用handleMessage的正確版本。
如果沒有某種單片開關/ case語句,我怎樣才能實現這一點。
您應該查看Double Dispatch模式。 請參閱此處的信息
您應該能夠將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)
這是因為Message :: dispatch將基於VisualMessage類型。 然后,當VisualMessage :: dispatch調用inMessageable.handleMessage(* this)時,它將調用正確的handleMessage,因為* this指針的類型是VisualMessage,而不是Message。
要修復您的代碼:
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,用於“額外的安全性”(假設有虛擬功能)。 但是設計意味着你知道self必須是一個指向S的指針,因為否則它不會向它注冊這個函數,你知道m必須引用一個T,因為它的typeid已經在dispatchMessage中被檢查過了。 因此,如果正確使用了類,則無法執行失敗的轉換,如果確實發生了,則所有可以執行的操作都是調試。
實際上我認為你也可以通過使bindFunction成為模板來減少措辭:
template <typename S, typename T>
void bindFunction(void)
{
m_handlers[&typeid(T)] = handle<S,T>;
}
然后用:
this->bindFunction<TestMessageable,VisualMessage>();
但是,你仍然可以看到為什么Steve Rowe的雙重調度代碼通常是首選......
這是一個古老的問題,但NUClear庫旨在提供快速和類型安全的消息傳遞,其方式與此問題的原始意圖類似。
完全披露:我是NUClear的聯合開發者之一
在這種情況下, 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.
});
}
您將在Scott Meyers的“更有效的C ++”中找到這樣的實現,而項目 - 31就是您想要的並且很好地解釋。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.