私は、コールバックを発生させる可能性のあるさまざまな種類の「イベント」と、イベントおよびその種類のイベントに固有のその他のカスタム プロパティ。
特定のイベント オブジェクトを受け取ることができるイベント マネージャと、イベントが発生したときに呼び出されるリスナー関数 (サブスクリプション) があります。
一部のイベントは特定の引数をリスナー コールバックに渡しますが、引数の型はイベントの種類によって異なります。
渡されたリスナー引数 (変数) がイベント オブジェクトに対して有効であることを検証する方法はありますか?
enum class EventKind {
first_kind, second_kind, third_kind
};
class EventBase {
public:
virtual EventKind kind() const = 0; // each subclass returns its EventKind identifier
virtual bool matches(const EventBase&) const = 0;
};
class FirstEvent : public EventBase {
public:
EventKind kind() const final { return EventKind::first_kind; }
bool matches(const EventBase&) const final; // compare kind and other properties
// other properties unique to FirstEvent
};
// other event subclasses ...
class EventManager {
public:
template<typename... Args>
void add_listener(const EventBase& event, std::function<void(Args...)> listener) {
// validation of Args... based on event.kind() goes here...
}
template<typename... Args>
trigger(const EventBase& event, Args... args) {
// called when event occurs
// internal lookup in the manager is done to find any listeners connected
// with this event object, and then we call it...
for (auto s : subscriptions[event.kind()]) {
if (event.matches(*(s->event))) {
auto* ss = dynamic_cast<Sub<Args...> *>(s);
if (ss && ss->listener) { ss->listener(args...); }
}
}
}
private:
struct SubBase {
EventBase* event;
};
template<typename... Args>
struct Sub : public SubBase {
std::function<void(Args...)> listener;
};
std::map<EventKind, std::vector<SubBase *>> subscriptions;
};
後でコールバックするためのリスナー関数を格納できる作業コードが既に用意されていますが (上記と同様)、Args... パラメーター パック/変数引数の一致は、イベントでイベントがトリガーされたときにのみ行われます。 manager - もちろん、元のリスナーの引数のセットが一致しない場合、それは呼び出されません (サイレント エラーが発生します)。
リスナーが追加されたときに、イベントの種類に基づいて (できればクラス階層を使用して)、この引数のリストを検証できると便利です。誰にもアイデアがありますか?
注: 現在、C++14 / Visual Studio 2014 / gcc 4.9.2 に制限されているため、C++17 の構成要素は使用できません。