gpt4 book ai didi

c++ - C++ 的自定义运行时类型系统/库

转载 作者:太空狗 更新时间:2023-10-29 23:19:25 25 4
gpt4 key购买 nike

在我目前制作的应用程序中,我有一个 EventDispatcher 类,它与基 Event 类一起使用。调度程序不是模板化的,它与每个事件的运行时类型一起工作;这是为了允许脚本从基础 Event 类继承并创建它们自己的事件类型。

它希望这个事件调度器也能处理事件的继承。例如,我有 FooEvent 继承自 FooBaseEvent;每当 FooEvent 发生时,对 FooBaseEvent 感兴趣的回调也会收到通知,但反之则不然。

是否有任何库可以使这更容易?请记住,继承检查也应该扩展到脚本中定义的事件。

(脚本语言是Python,不过应该没那么重要。)


编辑:我的EventDispatcher 具有以下接口(interface)(Python):

class EventDispatcher:
def subscribe(self, event_type, callback) -> EventDispatcher.Subscription
def post(self, event)

class Subscription:
def cancel(self)
def alive(self) -> bool

最佳答案

我不知道有任何图书馆可以让您的生活更轻松,但这并不能证明它不存在。也就是说,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_ (&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() 可能很慢。

关于c++ - C++ 的自定义运行时类型系统/库,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8929554/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com