Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>I'm not aware of any library that would make your life easier but that doesn't prove it doesn't exist. That said, the type system of Python and C++ have some important differences so it might be a bit tricky to find a general purpose type information system to bridge the two. </p> <p>If you only want to track the inheritance hierarchy and are prepared to manually register the types, you could roll your own relatively quickly. The following records the hierarchy in type_registry_t and then dispatcher_t looks at the hierarchy to see if a listener is interested in an event. Note uses some c++11 features.</p> <pre><code>#include &lt;iostream&gt; #include &lt;memory&gt; #include &lt;set&gt; #include &lt;string&gt; #include &lt;map&gt; #include &lt;vector&gt; typedef std::string class_id_t; class type_registry_t { std::multimap&lt;class_id_t, class_id_t&gt; parent_; public: void register_type(class_id_t const&amp; id, std::vector&lt;class_id_t&gt; const&amp; parent) { for (size_t i = 0, sz = parent.size(); i &lt; sz; ++i) parent_.insert(std::make_pair(id, parent[i])); } template &lt;class out_t&gt; out_t all_parents(class_id_t const&amp; id, out_t out) const { for (auto r = parent_.equal_range(id); r.first != r.second; ++r.first) { *out++ = r.first-&gt;second; out = all_parents(r.first-&gt;second, out); } return out; } }; class event_t { public: virtual class_id_t id() const = 0; virtual std::vector&lt;class_id_t&gt; parent() const = 0; }; inline void register_type(type_registry_t&amp; r, event_t const&amp; e) { r.register_type(e.id(), e.parent()); } class listener_t { std::vector&lt;class_id_t&gt; listen_for_; protected: listener_t(std::vector&lt;class_id_t&gt; const&amp; listen_for) : listen_for_ (listen_for) { } public: std::set&lt;class_id_t&gt; listen_for(type_registry_t const&amp; reg) const { std::set&lt;class_id_t&gt; s; for (size_t i = 0, sz = listen_for_.size(); i &lt; sz; ++i) { s.insert(listen_for_[i]); reg.all_parents(listen_for_[i], std::inserter(s, s.end())); } return s; } virtual void notify(event_t const&amp;) = 0; }; class dispatcher_t { type_registry_t const* reg_; std::vector&lt;std::shared_ptr&lt;listener_t&gt;&gt; listener_; public: dispatcher_t(type_registry_t const&amp; reg) : reg_ (&amp;reg) { } void connect(std::shared_ptr&lt;listener_t&gt; const listener) { listener_.push_back(listener); } void signal(event_t&amp; event) { class_id_t const id = event.id(); for (size_t i = 0, sz = listener_.size(); i &lt; sz; ++i) { std::set&lt;class_id_t&gt; const s = listener_[i]-&gt;listen_for(*reg_); if (s.find(id) != s.end()) listener_[i]-&gt;notify(event); } } }; </code></pre> <p>This lets you perform the selection of events based on their position in the hierarchy. As in the following (which is what I think you were describing in your example).</p> <pre><code>struct foo_base_event_t : event_t { class_id_t id() const { return "foo_base_event_t"; } std::vector&lt;class_id_t&gt; parent() const { std::vector&lt;class_id_t&gt; r; r.push_back("event_t"); return r; } }; struct foo_event_t : foo_base_event_t { class_id_t id() const { return "foo_event_t"; } std::vector&lt;class_id_t&gt; parent() const { std::vector&lt;class_id_t&gt; r; r.push_back("foo_base_event_t"); return r; } }; struct foo_event_listener_t : listener_t { static std::vector&lt;class_id_t&gt; relevant_ids() { std::vector&lt;class_id_t&gt; r; r.push_back("foo_event_t"); return r; } foo_event_listener_t() : listener_t (relevant_ids()) { } void notify(event_t const&amp; e) { std::cout &lt;&lt; "foo_event_listener_t::notify() with " &lt;&lt; typeid(e).name() &lt;&lt; " " &lt;&lt; (void*)&amp;e &lt;&lt; "\n"; } }; struct foo_base_event_listener_t : listener_t { static std::vector&lt;class_id_t&gt; relevant_ids() { std::vector&lt;class_id_t&gt; r; r.push_back("foo_base_event_t"); return r; } foo_base_event_listener_t() : listener_t (relevant_ids()) { } void notify(event_t const&amp; e) { std::cout &lt;&lt; "foo_base_event_listener_t::notify()" &lt;&lt; typeid(e).name() &lt;&lt; " " &lt;&lt; (void*)&amp;e &lt;&lt; "\n"; } }; int main() { type_registry_t reg; reg.register_type("event_t", std::vector&lt;class_id_t&gt;()); reg.register_type("foo_base_event_t", std::vector&lt;class_id_t&gt;(1, "event_t")); reg.register_type("foo_event_t", std::vector&lt;class_id_t&gt;(1, "foo_base_event_t")); dispatcher_t dispatcher (reg); dispatcher.connect(std::shared_ptr&lt;listener_t&gt;(new foo_event_listener_t())); dispatcher.connect(std::shared_ptr&lt;listener_t&gt;(new foo_base_event_listener_t())); foo_base_event_t foo_base_event; dispatcher.signal(foo_base_event); foo_event_t foo_event; dispatcher.signal(foo_event); return 0; } </code></pre> <p>You would need to expose some of this to Python, using your preferred method, to allow registration of event types. I have not included error checking and constructing the set of class_id's each call to listen_for() is probably slow.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload