I을 네 인생을 더 편하게 해주는 라이브러리는 모르지만 그것이 존재하지 않는다는 것을 증명하지는 못한다. 즉, Python과 C++의 타입 시스템에는 몇 가지 중요한 차이점이 있으므로 두 가지를 연결하는 범용 유형 정보 시스템을 찾는 것이 약간 까다로울 수 있습니다.
상속 계층 구조 만 추적하고 유형을 수동으로 등록 할 준비가되면 비교적 빨리 자신을 굴릴 수 있습니다. 다음은 type_registry_t의 계층을 기록한 다음 dispatcher_t는 계층을보고 리스너가 이벤트에 관심이 있는지 확인합니다. 참고 일부 C++ 11 기능을 사용합니다.
#include <iostream>
#include <memory>
#include <set>
#include <string>
#include <map>
#include <vector>
typedef std::string class_id_t;
class type_registry_t {
std::multimap<class_id_t, class_id_t> parent_;
public:
void register_type(class_id_t const& id, std::vector<class_id_t> const& parent)
{
for (size_t i = 0, sz = parent.size(); i < sz; ++i)
parent_.insert(std::make_pair(id, parent[i]));
}
template <class out_t>
out_t all_parents(class_id_t const& id, out_t out) const
{
for (auto r = parent_.equal_range(id); r.first != r.second; ++r.first) {
*out++ = r.first->second;
out = all_parents(r.first->second, out);
}
return out;
}
};
class event_t {
public:
virtual class_id_t id() const = 0;
virtual std::vector<class_id_t> parent() const = 0;
};
inline void register_type(type_registry_t& r, event_t const& e)
{
r.register_type(e.id(), e.parent());
}
class listener_t {
std::vector<class_id_t> listen_for_;
protected:
listener_t(std::vector<class_id_t> const& listen_for)
: listen_for_ (listen_for)
{ }
public:
std::set<class_id_t> listen_for(type_registry_t const& reg) const
{
std::set<class_id_t> s;
for (size_t i = 0, sz = listen_for_.size(); i < 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&) = 0;
};
class dispatcher_t {
type_registry_t const* reg_;
std::vector<std::shared_ptr<listener_t>> listener_;
public:
dispatcher_t(type_registry_t const& reg)
: reg_ (®)
{ }
void connect(std::shared_ptr<listener_t> const listener)
{
listener_.push_back(listener);
}
void signal(event_t& event)
{
class_id_t const id = event.id();
for (size_t i = 0, sz = listener_.size(); i < sz; ++i) {
std::set<class_id_t> const s = listener_[i]->listen_for(*reg_);
if (s.find(id) != s.end())
listener_[i]->notify(event);
}
}
};
이렇게하면 계층에서의 위치에 따라 이벤트를 선택할 수 있습니다. 다음과 같이 (이것은 내가 당신이 당신의 예에서 묘사 한 것이라고 생각합니다).
struct foo_base_event_t : event_t {
class_id_t id() const { return "foo_base_event_t"; }
std::vector<class_id_t> parent() const
{
std::vector<class_id_t> 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<class_id_t> parent() const
{
std::vector<class_id_t> r;
r.push_back("foo_base_event_t");
return r;
}
};
struct foo_event_listener_t : listener_t {
static std::vector<class_id_t> relevant_ids()
{
std::vector<class_id_t> r;
r.push_back("foo_event_t");
return r;
}
foo_event_listener_t()
: listener_t (relevant_ids())
{ }
void notify(event_t const& e)
{
std::cout << "foo_event_listener_t::notify() with " << typeid(e).name() << " " << (void*)&e << "\n";
}
};
struct foo_base_event_listener_t : listener_t {
static std::vector<class_id_t> relevant_ids()
{
std::vector<class_id_t> r;
r.push_back("foo_base_event_t");
return r;
}
foo_base_event_listener_t()
: listener_t (relevant_ids())
{ }
void notify(event_t const& e)
{
std::cout << "foo_base_event_listener_t::notify()" << typeid(e).name() << " " << (void*)&e << "\n";
}
};
int main()
{
type_registry_t reg;
reg.register_type("event_t", std::vector<class_id_t>());
reg.register_type("foo_base_event_t", std::vector<class_id_t>(1, "event_t"));
reg.register_type("foo_event_t", std::vector<class_id_t>(1, "foo_base_event_t"));
dispatcher_t dispatcher (reg);
dispatcher.connect(std::shared_ptr<listener_t>(new foo_event_listener_t()));
dispatcher.connect(std::shared_ptr<listener_t>(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;
}
선호하는 방법을 사용하여이 중 일부를 Python에 노출시켜야 이벤트 유형을 등록 할 수 있습니다. 오류 검사를 포함하지 않았고 class_id의 각 listen_for() 호출을 구성하는 것이 아마도 느립니다.
아마도 ZeroC ICE로 무엇인가 할 수 있습니다. C++과 Python을 바인딩합니다. –