私は自分のゲームのイベントシステムを書いています。それは正常に動作しますが、大きな欠点が1つあります。タイプセーフではないため、受信したベースイベントを手動でキャストするためにサブスクライブされたコールバック関数が必要です。今、テンプレートを使用して型保証バージョンを実装しようとしています。私は一般的にはトピックではOKですが、専門家ではないことは明らかです。イベントシステムの型付きの実装
が
// Derived Events
class ClickEvent : public Event
{
public:
float x;
float y;
};
class RenderNodeCreatedEvent : public Event
{
public:
unsigned long long int renderNodeId;
};
がそれらを作成派生イベントを定義し、(メインプログラムでテスト目的のために例えば)それらを使用
:まず、ここで私はイベントを使用する方法を示すいくつかのコードがありますここで
// Create the on event functions
std::function<void(const ClickEvent &)> onClickFunction = [](const ClickEvent & event)
{
std::cout << std::endl << "Mouse clicked at position: " << event.x << event.y;
};
std::function<void(const RenderNodeCreatedEvent &)> onRenderNodeCreatedFunction = [](const RenderNodeCreatedEvent & event)
{
std::cout << std::endl << "Render node created with id: " << event.renderNodeId;
};
// Create the events
ClickEvent clickEvent;
clickEvent.x = 300.f;
clickEvent.y = 255.5f;
RenderNodeCreatedEvent renderNodeCreatedEvent;
renderNodeCreatedEvent.renderNodeId = 26234628374324;
// Create the event manager and subscribe the event functions
EventManager eventManager;
eventManager.Subscribe(onClickFunction);
eventManager.Subscribe(onRenderNodeCreatedFunction);
// Raise the events
eventManager.Raise(clickEvent);
eventManager.Raise(renderNodeCreatedEvent);
私は各派生イベントクラスのタイプstd::size_t
のユニークなIDを生成しようとしたものです。
class BaseEvent
{
public:
typedef std::size_t ID;
BaseEvent() = default;
virtual ~BaseEvent() = default;
protected:
static ID GetNextID()
{
static ID id = 0;
return id++;
}
};
class Event : public BaseEvent
{
public:
Event() = default;
virtual ~Event() = default;
// Sets a unique id for the event the first time this function is called
ID GetID()
{
static ID id = BaseEvent::GetNextID();
return id;
}
};
最後に、これは上記の機能を提供できるイベントマネージャで私の(ひどい)試みです。私は実際のキャストを管理したり、さまざまなタイプのコールバック関数を格納するのに本当に苦労しています。コールバックラッパーは機能しません。私はこの問題を回避しなければならない基本的なアイデアなので、投稿に含めました。
これはコードがたくさんあることを知っていますが、これが私が話していることを実証する最も簡単な方法だと感じました。あなたの助けのための
おかげで、エイドリアン
EDIT: Eventクラスは派生型の一意のIDを取得するためのテンプレートとして宣言しなければならないであろう。
今template <class DerivedEvent>
class Event : public BaseEvent
イベント継承:
class ClickEvent : public Event<ClickEvent>
class RenderNodeCreatedEvent : public Event<RenderNodeCreatedEvent>
最後に、EventManagerは一部だけ長く研究した後
private:
std::vector<std::vector<TCallback<BaseEvent>>> callbackListList;
多分関連:https://stackoverflow.com/questions/47337029/handling-function-pointer-with-covariant-types-uniformly-how-to-call-callbacks – geza
もちろん、あなたが使用することはできません** BaseEvent **タイプのコールバックのベクトルのベクトルオブジェクトを基本オブジェクト型に格納すると、スライスが行われ、派生したオブジェクトの型とそのデータが失われます。ちなみに、コールバック型でマネージャを持つ方が簡単かもしれません。つまり、 'EventManager'はおそらく特定のタイプのコールバックを管理するテンプレートでなければなりません。そうすれば、型の安全性を達成するのは簡単です。 – Phil1970
@ Phil1970はい、私はリストにポインタを格納する必要があります。イベントマネージャーをテンプレートにする点について:私が望むのは、すべてのシステムが通信するために使用できるシングルイベントシステム(望むならメッセージシステム)ですから、これは私の目的に反するものです。 –